참치김밥은 최고의 한식이다

[Effective C# 2판] Item 7 : 튜플을 사용해서 타입의 사용 범위를 제한하라 본문

책/C#

[Effective C# 2판] Item 7 : 튜플을 사용해서 타입의 사용 범위를 제한하라

l__j__h 2024. 2. 21. 13:21

익명 타입

  • 컴파일러가 생성하는, 변경 불가능한 참조 타입
  • 사용법
var aPoint = new {x = 5, y = 67};

 

이 문장은 컴파일러에 여러 가지 사항을 알려주는데, 일단 internal sealed 클래스가 필요하다는 것과, 이 타입은 변경이 불가능하고, 2개의 읽기 전용 public 속성인 x, y가 필요하다는 것이다.

  • 장점 : 손으로 직접 sealed 클래스를 짜는 것보다, 컴파일러를 이용하는 편이 훨씬 수월하다. 컴파일러는 사람과 달리 정확히 동일한 코드를 빠르고 예외 없이 재생성해준다. 컴파일러에 코드 생성을 위임함으로써, 개발자가 직접 관리해야 할 코드를 최소화할 수 있다. 즉, 이해하거나 검토해야 할 코드가 줄어든다.
  • 단점 : 이 타입은, 매개변수를 전달할 수도 없고, 반환값의 타입으로 사용할 수도 없다. 단, 람다 표현식이나 익명 델리게이트를 활용해서 익명 타입으로 생성한 객체를 사용할 수 있다. 여러 단계를 거쳐야 하는 알고리즘을 수행할 때, 각 단계의 결과를 임시 저장하기 위해 사용할 때에 편하다.

 

static T Transform<T>(T element, Func<T,T> transformFunc){
	return transformFunc(element);
}

var aPoint = new {x=5, y=67};
var anotherPoint = Transform(aPoint, (p)=>new {x= p.x*2, y=p.y*2};
  • 익명 타입 객체를 생성할 때, 앞서 생성한 익명 타입 객체의 속성의 이름과 타입이 불일치하거나, 속성을 선언하는 순서가 다르면, 서로 다른 익명 타입으로 간주된다.

 

var aPoint = new {x=5, y=67};
var anotherPoint = new {y=5, x=5};
//위 둘은 서로 다른 타입으로 간주된다. 속성을 선언하는 순서가 다르기 때문이다.
  • 익명 타입은 동일성을 검사할 때, 값의 내용을 기반으로 하기 때문에 복합키로 사용할 수 있다. 예를 들어, 고객을 영업 담당자와 우편번호를 기준으로 묶어 아래와 같은 쿼리를 수행할 수 있다.
var query = from c in customers group c by new {c.SalesRep, c.ZipCode};

 

이 쿼리는 영업 담당자(SalesRep)와 우편번호(ZipCode) 쌍을 키로 지니는 Dictionary를 반환한다. 결과값은 고객의 목록이다. 즉, Dictionary<(SalesRep, ZipCode), customer> 를 생성하는 듯 하다.

 

튜플

  • 익명 타입과 달리, public 필드를 포함하는 변경 가능한 값 타입이다.
  • 익명 타입과 달리, 튜플을 인스턴화하면, 완전히 새로운 타입을 생성하는 것이 아니라, ValueTuple 제네릭 구조체를 이용하여 닫힌(closed) 제네릭 타입을 생성한다. (이미 필드의 개수별로 여러 개의 ValueTuple 제네릭 타입이 정의되어 있다.)

익명 타입과 튜플 중 하나를 선택할 때에는 두 타입의 차이를 고려해야 한다. 튜플은 구조적 타이핑을 따르므로, 메서드의 반환 ㅊ타입이나 매개변수의 타입으로 사용하기에 적합하다. 익명 타입은 변경 불가능한 타입을 정의할 대나, 컬렉션의 복합키로 사용하기 좋다.(이건 진짜 유용하다) 튜플은 값 타입의 장점을 모두 가지는 반면, 익명 타입은 참조 타입이 가지는 장점을 모두 가진다.

728x90