쇼트컷 시리즈 (Type Inference)
참조 :
LINQ: The Future of Data Access in C# 3.0 책 구매는
-> http://oreilly.com/catalog/9780596528416/ 소스 다운은
-> http://examples.oreilly.com/language1/ Lambda expression을 설명하면서 anonymous
method에 대해서도 같이 설명을 했었는데 이 두 기능에서는 아주 미묘한 차이점이 있다. Anonymous
method의 경우는 타입정보가 필요하다는 것이고 Lambda expression의 경우는
그렇지 않다는 것이다. Lambda expression에서 예를 들었던 하나의 문장을 살펴보자. d => d.City == "Chicago" 여기에는 d의 타입에 대해서 명시한
문장이 없다. 즉 타입이 없다면 컴파일러는 Lambda
expression을 anonymous method로 변경할 수가 없다. delegate(???? d) {
return d.City == “Chicago”; } 이러한 작업을 성공시키기 위해서는 특별한 하나의 단계가 필요한데 C# 3.0에서는 inferring(추론)이라는 작업을 한다. 즉
lambda expression에 있는 d가 어떤 타입인가를 추론하게 되고 이러한 추론작업의
근거가 되는 것이 문맥 정보(Contextual Information)이다. 예를 들면 doctors의 타입은 List<Doctor>라는 건데 컴파일러가 컴파일을 하면서 d는 FindAll을 호출하는 doctors의 일부라고 판단하기 때문에 d에 대한 타입을 결정하게 된다. doctors.FindAll(d => d.City == “Chicago”); 이러한 Type Inference가
무엇보다도 안전성과 성능에 영향이 없는 상태에서 LinQ를 사용할 수 있도록 해준다. 다시 말하면 개발자가 참 편하게 개발을 할 수 있도록 해 주는 것이다. 또한
이러한 모든 부분들이 컴파일 시점에서 문맥 체크를 통해서 자동으로 생성 되기 때문에 더욱더 안정성을 보장해 주는 역할을 하게 된다. 지금부터는 var에 대해서 알아보자. 타입 추론에 의해서 var키워드를 사용할 경우 문맥 정보에 의해서
자동으로 변수에 대한 타입을 컴파일 시에 지정을 하게 된다. 예를 들어 아래와 같이 지정을 하자. var sum = 0; var avg = 0.0; var obj = new Doctor(…); 이렇게 하면 sum의 경우는 문맥 정보에 의해서 int타입으로 avg의 경우는 double, Doctor의 경우는 obj형태로 컴파일을 할 때 타입추론을 하게 된다. 하지만 한번 정의된 타입을 다른 형태로 바꾸려는 코드나 문맥 정보가 없는 형태로 선언을 할 경우 컴파일 할 때 에러가 발생한다. 그리고 애매한 형태로 선언하려는 경우 즉, null값을 할당하려는
경우에도 에러가 발생한다. 위에서 설명한 내용을 잘 생각해보면 어쩌면 당연한 논리일 것이다. var obj; // 문맥정보가 없기 때문에 에러가 발생한다. var obj3 = null;
// 에러가 발생한다. var obj2 = “1”; obj2 = 1; // 타입 변환에 에러가 발생을 한다. 한가지 염두에 두어야 할 부분이 있는데, javascript와 같은 언어에서var는 런타임에서 형이 변환되어도 문제가 없다. 하지만 C# 3.0에서의 var 키워드는 컴파일 할 때에 타입을 체크하기 때문에
이 부분에서의 차이점을 늘 생각하면서 코딩을 해야 할 것이다. 또다른 예를 살펴보자. object obj = "hi"; var obj2 = obj; 여기까지는
문제가 없다. 하지만 obj에 문자열을 할당했다고 해서 obj2까지 문자열과 같은 속성을 가지는 것은 아니다. 즉, string s1 = obj2.ToUpper(); 처럼
사용할 수가 없다. 컴파일러가 가장 최소한의 기능을 가진 객체로 설정을 해 버리기 때문이다. 자 이제 LinQ의 일반적인 소스를 보면서 다시 한번 더 상기시켜보자. var query = from d in doctors where d.City ==
"Chicago" select new { d.GivenFirstName,
d.FamilyLastName }; // type? foreach (var r in query) System.Console.WriteLine("{0},
{1}", r.FamilyLastName, r.GivenFirstName); 여기에서 query의 타입은 과연 어떻게 될까? D의
경우은 타입 추론에 의해서 List<Doctor>라는 것을 쉽게 알 수 있을 것이다. 그럼 query는? Select new라는
형태를 보면 새롭게 타입이 생성되는 것을 알 수가 있다. 아마도 컴파일러가 적절한 List<T> 객체를 만들지 않을까 라는 생각이 든다. 다음 시간에는 이 부분에 대해서 자세하게 썰을 풀어볼 생각이다.