2011-05-04 7 views
12

다음 (무의미하지만, 그림 목적의) 테스트 클래스 :동적 LINQ와 선택()

public class Test 
{ 
    public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
    { 
     return t.Select(x => ToStr(x)); 
    } 

    public IEnumerable<string> ToEnumerableStrsWillCompile(IEnumerable<dynamic> t) 
    { 
     var res = new List<string>(); 

     foreach (var d in t) 
     { 
      res.Add(ToStr(d)); 
     } 

     return res; 
    } 

    public string ToStr(dynamic d) 
    { 
     return new string(d.GetType()); 
    } 
} 

는 왜 t.Select(x => ToStr(x))에 다음과 같은 오류와 함께 컴파일되지 않습니다?

Cannot implicitly convert type 'System.Collections.Generic.IEnumerable<dynamic>' 
to 'System.Collections.Generic.IEnumerable<string>'. An explicit conversion 
exists (are you missing a cast?) 

두 번째 방법에는 오류가 없습니다.

답변

10

시도

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select<dynamic, string>(x => ToStr(x)); 
} 
+2

+1 설명과 특히 방법 그룹 버전 –

1

는 다음과 같이하십시오 :

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(ToStr); 
} 

또 다른 가능성을 명시 적으로 일반 인수를 지정하는 것입니다 : 내가 여기에서 발생하는 것은 생각 return t.Select(x => ToStr(x)) as IEnumerable<string>

+1

작동하지만 그 이유는 무엇입니까? – mathieu

1

을 표현 ToStr(x)을 포함하기 때문에 그 dynamic 변수의 경우 전체 표현식의 결과 유형도 dynamic입니다. 그 이유는 컴파일러가 IEnumerable<string>을 기대하는 IEnumerable<dynamic>을 가지고 있다고 생각하는 이유입니다.

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(x => ToStr(x)); 
} 

두 가지 방법으로 문제를 해결할 수 있습니다.

는 명시 적 캐스트 사용

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(x => (string)ToStr(x)); 
} 

이는 식의 결과가 확실히 문자열이 될 것입니다 컴파일러를 알려줍니다를, 그래서 우리는 IEnumerable<string>로 끝날.

는 방법기로 람다 바꾸기 :

public IEnumerable<string> ToEnumerableStrsWontCompile(IEnumerable<dynamic> t) 
{ 
    return t.Select(ToStr); 
} 

이 방법 컴파일러 암시 람다에있어서 그룹 표현으로 변환한다. 표현식에 dynamic 변수 x에 대한 언급이 없으므로 고려해야 할 메소드가 하나뿐이기 때문에 그 결과의 유형을 즉시 string으로 추측 할 수 있으며 리턴 유형은 string입니다.

+2

작동하지만, 그 이유는 무엇입니까? – mathieu

1

IT는 C# 컴파일러는 Func<dynamic, dynamic>x => ToStr(x) 첫번째 방법에서, λ의 유형을 결정하고, 따라서이 IEnumerableIEnumerable<dynamic> 반환 유형을 선언되는 것으로 생각된다. 작은 변화 x => (string)ToStr(x)는 그것을 고쳐주는 것처럼 보입니다.

이 때문에 타입 추론 규칙의 가능성이 높습니다 -이로 라인을 변경하는 경우 때문에 :

return t.Select<dynamic, string>(x => ToStr(x)); 

그것은 오류없이 컴파일합니다.

문제의 특정 유형의 추론 규칙, 그러나 나는 너무 확실하지 않다 -이 코드를 가지고 있지만 경우 :

public void foo(dynamic d) 
{ 
    var f = this.ToStr(d); 
    string s = f; 
} 

을 그리고 당신이 볼 수 편집기에서 'F'위에 마우스를 올려 그 intellisense는 표현의 유형을 '동적 f'로보고합니다.이것은 this.ToStr(d)이 메소드 자체와 그 리턴 유형이 컴파일시인지 여부에 관계없이 동적 표현식이기 때문입니다.

궁극적으로 ToStr은 항상 문자열을 반환하기 때문에 컴파일러는 f이 될 가능성이있는 유형을 정적으로 분석 할 수 있기 때문에 string s = f;을 할당하게됩니다.

컴파일러에서 ToStrdynamic 유형이되기 때문에 첫 번째 방법은 캐스트 또는 명시 적 유형 매개 변수가 필요한 이유입니다. 그것의 일부로 최소한 하나의 동적 인 표현이 있기 때문입니다.