developer tip

겉보기에 간단하고 명백한 사례에서 C #이 유형을 추론 할 수없는 이유

copycodes 2020. 11. 12. 08:26
반응형

겉보기에 간단하고 명백한 사례에서 C #이 유형을 추론 할 수없는 이유


이 코드가 주어지면 :

class C
{
    C()
    {
        Test<string>(A); // fine
        Test((string a) => {}); // fine
        Test((Action<string>)A); // fine

        Test(A); // type arguments cannot be inferred from usage!
    }

    static void Test<T>(Action<T> a) { }

    void A(string _) { }
}

컴파일러는 불평 Test(A)을 알아낼 수 없습니다 Tstring.

이것은 나에게 매우 쉬운 경우처럼 보이며 내가 작성한 다른 일반 유틸리티 및 확장 함수에서 훨씬 더 복잡한 추론에 의존했습니다. 내가 여기서 무엇을 놓치고 있습니까?

업데이트 1 : 이것은 C # 4.0 컴파일러에 있습니다. VS2010에서 문제를 발견했으며 위의 샘플은 LINQPad 4에서 만든 가장 간단한 사례 재현에서 가져온 것입니다.

업데이트 2 : 작동하는 항목 목록에 몇 가지 예를 추가했습니다.


Test(A);

적용 가능한 유일한 메서드 ( Test<T>(Action<T>))에는 유형 추론이 필요하고 유형 추론 알고리즘에서는 각 인수가 특정 유형이거나 익명 함수 여야 하므로 실패 합니다. (이 사실은 형식 유추 알고리즘 (§7.5.2)의 사양에서 유추 됨) 메서드 그룹 A은 어떤 형식도 아니며 (적절한 대리자 형식으로 변환 할 수 있음에도 불구하고) 익명 함수가 아닙니다.

Test<string>(A);

이것은 성공합니다. 차이점은 Test를 바인딩하는 데 형식 유추가 필요하지 않으며 메서드 그룹 A를 필요한 대리자 매개 변수 형식으로 변환 할 수 있다는 것 void Action<string>(string)입니다.

Test((string a) => {});

이것은 성공합니다. 차이점은 형식 유추 알고리즘이 첫 번째 단계 (§7.5.2.1)에서 익명 함수를 제공한다는 것입니다. 익명 함수의 매개 변수 및 반환 형식이 알려져 있으므로 명시적인 매개 변수 형식 유추를 수행 할 수 있으며 익명 함수 void ?(string)의 형식 ( )과 Test메서드 매개 변수 의 대리자 형식 ( )의 형식 매개 변수 간에 대응이 이루어집니다. void Action<T>(T)). 익명 함수에 대해이 알고리즘에 해당하는 메소드 그룹에 대해 지정된 알고리즘이 없습니다.

Test((Action<string>)A);

이것은 성공합니다. 차이점은 유형이 지정되지 않은 메소드 그룹 매개 변수 A가 유형으로 캐스트되어 Test메소드에 대한 유일한 인수로 특정 유형의 표현식을 사용 하여 유형 추론이 정상적으로 진행될 수 있다는 것입니다.

나는 이론상 왜 메소드 그룹에서 과부하 해결을 시도 할 수 없는지에 대한 이유를 생각할 수 없습니다 A. 그런 다음 최상의 바인딩이 하나만 발견되면 메서드 그룹에 익명 함수와 동일한 처리를 할 수 있습니다. 이는 메소드 그룹에 정확히 하나의 후보가 포함되고 유형 매개 변수가없는 이와 같은 경우에 특히 그렇습니다. 그러나 C # 4에서 작동하지 않는 이유는이 기능이 설계 및 구현되지 않았기 때문인 것으로 보입니다. 이 기능의 복잡성, 응용 프로그램의 순박함 및 세 가지 쉬운 해결 방법의 존재를 감안할 때 나는 숨을 참지 않을 것입니다!


2 단계 추론이기 때문이라고 생각합니다.

  • A를 일반 델리게이트로 변환하고 싶다고 추론해야합니다.

  • 위임 매개 변수의 유형이 무엇인지 추론해야합니다.

이것이 이유인지 확실하지 않지만 내 직감은 2 단계 추론이 컴파일러에게 반드시 쉬운 것은 아니라는 것입니다.


편집하다:

직감이지만 첫 번째 단계가 문제라는 것을 알려주는 것이 있습니다. 컴파일러는 다른 수의 제네릭 매개 변수 를 사용하여 대리자로 변환해야 하므로 매개 변수 유형을 추론 할 수 없습니다.


이것은 나에게 악순환처럼 보입니다.

Test메서드에는 제네릭 형식에서 구성된 대리자 형식의 매개 변수가 필요합니다 Action<T>. 대신 메서드 그룹을 전달 Test(A)합니다.. 즉, 컴파일러는 매개 변수를 대리자 형식으로 변환해야합니다 ( 메서드 그룹 변환 ).

But which delegate type? To know the delegate type we need to know T. We didn't specify it explicitly, so compiler has to infer it to figure out the delegate type.

To infer the type parameters of the method we need to know the types of the method arguments, in this case the delegate type. Compiler doesn't know the argument type and thus fails.

In all other cases either type of argument is apparent:

// delegate is created out of anonymous method,
// no method group conversion needed - compiler knows it's Action<string>
Test((string a) => {});

// type of argument is set explicitly
Test((Action<string>)A); 

or type parameter is specified explicitly:

Test<string>(A); // compiler knows what type of delegate to convert A to

P.S. more on type inference


You're passing the name of the Method A. The .Net framework CAN convert it to an Action, but it's implicit and it will not take responsibility for it.

But still, a method name is NOT an explicit Action<> Object. And therefor it won't infer the type as an Action type.


I could be wrong, but I imagine the real reason C# cannot infer the type is due to method overloading and the ambiguity that arises. For example, suppose I have the following methods: void foo (int) and void foo (float). Now if I write var f = foo. Which foo should the compiler pick? Likewise, the same problem happens with your example using Test(foo).

참고URL : https://stackoverflow.com/questions/6229131/why-cant-c-sharp-infer-type-from-this-seemingly-simple-obvious-case

반응형