2014-04-22 3 views
5

오류가있는 줄에서 컴파일러가 T 매개 변수가있는 메서드를 해상도로 선택하기 때문에 컴파일되지 않습니다. 이는 List<T>이 a의 일반 제약 조건에 맞지 않기 때문에 실패합니다. 싱글 T. 컴파일러는 사용할 수있는 또 다른 메소드가 있음을 인식하지 못합니다. 단일 T 메서드를 제거하면 컴파일러에서 여러 개체에 대한 메서드를 올바르게 찾습니다.일반 확장 메서드 확인이 실패합니다.

일반적인 방법 해상도에 대한 블로그 게시물 두 개를 읽었습니다. 하나는 JonSkeet here이고 다른 하나는 Eric Lippert here에서 가져 왔지만 설명이나 문제를 해결할 방법을 찾을 수 없습니다.

분명히, 다른 이름을 가진 두 가지 메소드를 사용하면 효과가있을 것입니다. 그러나 저는이 경우에 대해 하나의 메소드가 있다는 점을 좋아합니다. 드미트리 제안으로 두 번째를 다음과 같은 방법으로 호출하여,

public static void Method(this SomeInterface parameter) { /*...*/ } 

을 또는 :

instances.Method<SomeImplementation>(); 
namespace Test 
{ 
    using System.Collections.Generic; 

    public interface SomeInterface { } 

    public class SomeImplementation : SomeInterface { } 

    public static class ExtensionMethods 
    { 
    // comment out this line, to make the compiler chose the right method on the line that throws an error below 
    public static void Method<T>(this T parameter) where T : SomeInterface { } 

    public static void Method<T>(this IEnumerable<T> parameter) where T : SomeInterface { } 
    } 

    class Program 
    { 
    static void Main() 
    { 
     var instance = new SomeImplementation(); 
     var instances = new List<SomeImplementation>(); 

     // works 
     instance.Method(); 

     // Error 1 The type 'System.Collections.Generic.List<Test.SomeImplementation>' 
     // cannot be used as type parameter 'T' in the generic type or method 
     // 'Test.ExtensionMethods.Method<T>(T)'. There is no implicit reference conversion 
     // from 'System.Collections.Generic.List<Test.SomeImplementation>' to 'Test.SomeInterface'. 
     instances.Method(); 

     // works 
     (instances as IEnumerable<SomeImplementation>).Method(); 
    } 
    } 
} 
+0

'instances.Method ();'을 (를) 사용해 보셨습니까? – Dmitry

+0

@ 드미트리는 실제로 작동 할 것입니다. 나는 몇 가지 것을 시험 할 것이다. – nvoigt

답변

6

방법 해상도는 closer is better을 말한다. 정확한 규칙은 블로그 게시물을 참조하십시오.

더 가까운 의미는 무엇입니까? 컴파일러는 정확한 일치를 찾을 수 있는지, 어떤 이유로 찾을 수없는 경우 다음 가능한 호환 방법 등을 찾을 것입니다.

우선 SomeInterface 제약 조건을 제거하여 해당 메소드를 컴파일 해 보겠습니다.

public static class ExtensionMethods 
{ 
    public static void Method<T>(this T parameter) //where T : SomeInterface 
    { } 

    public static void Method<T>(this IEnumerable<T> parameter) //where T : SomeInterface 
    { } 
} 

이제 컴파일러는 컴파일 할 행복, 두 방법은 Method(T)보다는 Method(IEnumerable<T>)로 이동 호출 있습니다 않습니다. 왜 그런가요?

Method(T)은 모든 유형을 매개 변수로 사용할 수 있고 변환을 필요로하지 않기 때문에 더 가깝기 때문에.

Method(IEnumerable<T>)이 가까이 있지 않습니까?

List<T>로 변수의 컴파일시의 형태를 가지고 있기 때문이다, 그래서 List<T>에서 IEnumerable<T>에 대한 참조 변환이 필요합니다. 더 가까이에 있지만 전혀 전환을하지 않는 것입니다.

질문으로 돌아 가기.

instances.Method();이 컴파일되지 않습니까?

앞서 언급했듯이 Method(IEnumerable<T>)을 사용하면 참조 변환이 필요하므로 분명히 그 것이 더 가까이 있지 않습니다. 이제는 매우 가까운 한 가지 방법 만 남았습니다. Method<T>입니다. 그러나 문제는 SomeInterface으로 제한했으며 List<SomeImplementation>()SomeInterface으로 변환 할 수 없음을 분명히 나타냅니다.

컴파일러가 더 가까운 과부하를 선택하면 문제가 발생합니다 (추측) 일반 제약 조건 검사가 발생합니다. 이 경우 선택한 최상의 과부하가 무효화됩니다.

변수의 정적 유형을 IEnumerable<SomeImplementation>으로 변경하면 쉽게 해결할 수 있습니다. 이제는 그 이유를 알 수 있습니다.

IEnumerable<SomeImplementation> instances = new List<SomeImplementation>(); 
+0

좋아, 그게 실제로 내 문제를 해결하지 않습니다 (나는 사람들이 놀라움없이 그것을 사용할 수 있도록 다른 이름을 지어라.). 그러나 적어도 그것은 꽤 좋은 설명이다 * 왜 *. – nvoigt

1

는이 같은 행동해야으로, 제네릭이없는 첫 번째 구현을 시도 되세요

하지만 여기에 모든 전화에 <SomeImplementation>을 추가해야합니다.

+0

그게 좋은 생각입니다. 어쩌면 나는 나의 모범을 보완해야했다. 실제 프로젝트에서 T는 * 두 개의 다른 인터페이스를 구현하는 데 제약이 있습니다. 이는 제네릭을 사용하는 이유입니다. – nvoigt

+0

아, 그래. 그 경우에는 내 아이디어가 작동하지 않습니다 (하지만이 경우 작동합니다 - 그냥 테스트) ... – ChrFin

+0

나는 많은 것들을 시도하고 두 경우 모두 제네릭과 함께 작동하도록 추가 코드없이 메서드를 호출하지 못했습니다 및 IMO 작동합니다 - 어쩌면 다른 사람이이 동작에 약간의 표시등을 흘릴 수 있습니다 (또는 실제로 메서드를 해결 버그가 있습니다) ... – ChrFin

1
  1. 나는 그것을 원하지 않는다는 것을 알고 있지만, 메소드 이름이 같아야한다면 정말로 생각해야한다고 생각한다. 같은 이름이 인스턴스에서 어떻게 작동 할 수 있는지, 그러한 인스턴스의 수집을 볼 수 없습니다. 예를 들어, 메서드 이름이 T의 경우 Shoot 인 경우 다른 메서드는 ShootThemAll 또는 비슷한 것으로 표시되어야합니다.

  2. 아니면 당신은 당신의 할당이 약간 다른해야한다 : 마지막 옵션으로

    IEnumerable<SomeImplementation> instances = new List<SomeImplementation>(); 
    instances.Method(); //now this should work 
    
  3. , 드미트리 댓글에 말한대로 명시 적으로 형식 인수를 지정해야합니다.

    instances.Method<SomeImplementation>(); 
    
관련 문제