2012-02-25 5 views
28

을 쓴 이해 :전개 된 IEnumerable <IEnumerable <>>; 나는 (컴파일)이 확장 방법 제네릭

public static IEnumerable<J> Flatten<T, J>(this IEnumerable<T> @this) 
              where T : IEnumerable<J> 
{ 
    foreach (T t in @this) 
     foreach (J j in t) 
      yield return j; 
} 

아래의 코드는 컴파일 타임 오류가 발생이 (더 적합한 방법을 찾을 수 없음), 이유는 무엇입니까? :

public static IEnumerable<J> Flatten<J>(this IEnumerable<IEnumerable<J>> @this) 
{ 
    foreach (IEnumerable<J> js in @this) 
     foreach (J j in js) 
      yield return j; 
} 

편집 (2)

: 나는 다음과 같은 확장 기능을 구현하는 경우

IEnumerable<IEnumerable<int>> foo = new int[2][]; 
var bar = foo.Flatten(); 

, 나는 어떤 컴파일 타임 오류 얻을 내가 생각이 질문에 대답을하지만, 대한 또 다른 질문을 제기 과부하 해결 및 유형 제약. 이 질문에 내가 여기에 넣어 : Why aren't type constraints part of the method signature?

+1

주위에 많은 열거 형이 있으므로 편집하지 않습니다. 'foo.Flatten , int>();'가 작동해야합니다. – dlev

답변

65

먼저 Flatten() 필요하지 않습니다; 해당 메서드는 이미 존재하며 SelectMany()이라고합니다. 당신은 다음과 같이 사용할 수 있습니다 : 일반적인 형식 유추는 메서드에 인수에만 기반으로 작동하기 때문에

IEnumerable<IEnumerable<int>> foo = new [] { new[] {1, 2}, new[] {3, 4} }; 
var bar = foo.SelectMany(x => x); // bar is {1, 2, 3, 4} 

둘째, 첫 번째 시도가 작동하지 않습니다, 메소드와 연관된 일반적인하지 제약. J 제네릭 매개 변수를 직접 사용하는 인수가 없으므로 형식 유추 엔진은 J이 무엇인지 추측 할 수 없으므로 메서드가 후보라고 생각하지 않습니다.

SelectMany()가이 문제를 얻는 방식을 볼 수 교화 : 그것은 추가로 Func<TSource, TResult> 인수가 필요합니다. 이를 통해 형식 유추 엔진은 두 가지 제네릭 형식을 모두 결정할 수 있습니다. 두 형식 모두 메서드에 제공된 인수를 기반으로 사용할 수 있기 때문입니다.

+1

@Daryl : 'Flatten , int> (foo)'이어야합니다. – BrokenGlass

+2

@Daryl 일반 제약은 메소드 서명의 일부로 간주되지 않습니다. * more more *에 대한 자세한 내용은 다음 링크를 참조하십시오. http://blogs.msdn.com/b/ericlippert/archive/2009/12/10/constraints-are-not-part-of-the-signature.aspx – dlev

+1

@Daryl :하지 마세요. 여기에 학습 곡선이 분명히 있습니다. 이해하는 것이 C#의 가장 쉬운 측면은 아닙니다.그냥 마스터하려고하면 이미 나머지 95 %를 앞설 것입니다 .-) – BrokenGlass

13

dlev의 답변은 괜찮습니다. 나는 방금 좀 더 많은 정보를 추가 할 것이라고 생각했습니다.

는 특히, 나는 당신이 IEnumerable<T>에 공분산의 종류를 구현하기 위해 제네릭을 사용하려고 있습니다. C# 4 이상에서는 IEnumerable<T>이 이미 공변입니다.

두 번째 예는 이것을 보여줍니다. 당신이

List<List<int>> lists = whatever; 
foreach(int x in lists.Flatten()) { ... } 

이있는 경우 다음 List<int>IE<int>로 변환하고, 추론 List<List<int>>IE<List<int>>로 변환 것으로 추론됩니다 입력, 따라서 때문에 공분산의, IE<List<int>>IE<IE<int>>로 변환합니다. 그것은 타입 추론을 할 것입니다. T는 int이고 모든 것이 좋다는 것을 추론 할 수 있습니다.

이것은 C# 3에서 작동하지 않습니다. 공분산이없는 세상에서의 삶은 조금 더 어려워 지지만 Cast<T> 확장 방법을 신중히 사용하면 얻을 수 있습니다.

관련 문제