2016-06-17 1 views
5

는 다음과 같은 두 가지 확장 방법을 고려 : 내 두 번째 방법을 썼을 때컴파일러는 IEnumerable <T>을 통해 IEnumerable로 대체를 선택하는 이유는 무엇입니까?

using System; 
using System.Collections.Generic; 
using System.Linq; 

public static class Extensions 
{ 
    public static bool Contains(this IEnumerable self, object obj) 
    { 
     foreach (object o in self) 
     { 
      if (Object.Equals(o, obj)) 
      { 
       return true; 
      } 
     } 
     return false; 
    } 

    public static bool ContainsEither<T>(this IEnumerable<T> self, T arg1, T arg2) 
    { 
     return self.Contains(arg1) || self.Contains(arg2); 
    } 
} 

, 나는 일반 LINQ Enumerable.Contains<T> 방법 (사용에서 추론 형식 인수)를 호출 할 의도. 그러나, 나는 실제로 첫 번째 방법을 호출하는 것을 발견 (내 사용자 지정 Contains() 확장 방법은. 내 Contains() 방법을 언급 할 때, 두 번째 방법은 Enumerable.Contains<T>() 방법을 사용하여, 잘 컴파일합니다.

내 질문은, 왜 않습니다 컴파일러는 IEnumerable<T> 인수 Enumerable.Contains<T>() 이상의 제네릭이 아닌 IEnumerable 인수로 내 Contains() 방법을 선택 나는 그것이 IEnumerable<T>IEnumerable보다 파생 Enumerable.Contains<T>() 때문에 선택하는 기대

업데이트 :.. 위대한 답변 존 소총 덕분에 그것은 것 디자이너가 이런 식으로 선택한 이유를 알고 흥미 롭습니다. 이 상관 할 곳이야, 내가 한 생각 (그것이 손이 닿지 약간의 부여)

public static double Average(this IEnumerable self) 
{ 
    double sum = 0; 
    long count = 0; 
    foreach (object obj in self) 
    { 
     sum += Convert.ToDouble(obj); 
     nItems++; 
    } 
    return sum/count; 
} 

object[] junk = new object[] { "9000", (byte)99, -8.555, 3154254325345UL }; 
double[] clean = new double[] { 9000, 99, -8.555, 3154254325345 }; 
double junkAvg = junk.Average(); 
double cleanAvg = clean.Average(); // compiler is choosing your Average() method where you'd prefer it to choose Enumerable.Average(IEnumerable<double>) 
+0

제네릭이 더 구체적입니다. –

+0

일반적으로 이와 같은 상황에서 "왜"라는 질문은 일반적으로 흥미 롭습니다.하지만 아마도 "어떻게하지 않습니까?"라는 질문이 더 중요 할 것입니다. –

+0

@ LasseV.Karlsen 정말 이유에 대해서. Enumerable.Contains (...) 또는 Contains (...)을 쓸 수있었습니다. –

답변

20

, 왜 컴파일러는 제네릭이 아닌 IEnumerable 인수 Enumerable.Contains<T>() 이상으로) (내가 포함 방법을 선택 않는 내 질문 IEnumerable<T> 인수가 있습니까?

동일한 네임 스페이스에서이를 호출하는 메서드가 있기 때문에 발견되었습니다. 해당 네임 스페이스 내에서 선언 된 형식은 가져온 네임 스페이스에서 선언 된 형식보다 우선적으로 우선합니다. 는 C# 5 사양에서

, 섹션 7.6.5.2 :

다음과 같이 C 진행에 대한 검색 :

  • 는 가장 가까운 바깥 쪽 네임 스페이스 선언을 시작으로 각 둘러싸는 네임 스페이스 선언을 계속, 포함 된 컴파일 단위로 끝나는 경우 확장 메소드의 후보 집합을 찾기 위해 연속 시도가 수행됩니다.
    • 주어진 네임 스페이스 또는 compilatio n 단위는 직접적으로 적절한 확장 방법 Mj를 갖는 비 제네릭 타입 선언 Ci를 포함하고, 그 확장 방법 집합이 후보 집합이된다.
    • 주어진 네임 스페이스 또는 컴파일 단위의 네임 스페이스 지시문을 사용하여 가져온 네임 스페이스에 적절한 확장 메서드 Mj가있는 비 제네릭 형식 선언 Ci가 직접 포함되어 있으면 해당 확장 메서드 집합이 후보 집합입니다.
  • 포함 집합의 네임 스페이스 선언 또는 컴파일 단위에서 후보 세트가 발견되지 않으면 컴파일 타임 오류가 발생합니다.
관련 문제