C# 3.0 일반 유형 추론 - 대의원을 함수 매개 변수로 전달
-
03-07-2019 - |
문제
C# 3.0 컴파일러가 왜 동일한 메소드에 대한 대의원을 암시 적으로 생성 할 수있을 때 매개 변수로 전달 될 때 메소드 유형을 추론 할 수없는 이유가 궁금합니다.
예는 다음과 같습니다.
class Test
{
static void foo(int x) { }
static void bar<T>(Action<T> f) { }
static void test()
{
Action<int> f = foo; // I can do this
bar(f); // and then do this
bar(foo); // but this does not work
}
}
나는 내가 통과 할 수 있다고 생각했을 것이다 foo
에게 bar
컴파일러가 유형의 유형을 유추하게하십시오 Action<T>
전달되는 함수의 서명에서 이것은 작동하지 않습니다. 그러나 나는 만들 수있다 Action<int>
~에서 foo
캐스팅 없이는 컴파일러가 유형 추론을 통해 같은 일을 할 수 없다는 합법적 인 이유가 있습니까?
해결책
어쩌면 이것은 더 명확하게 만들 것입니다 :
public class SomeClass
{
static void foo(int x) { }
static void foo(string s) { }
static void bar<T>(Action<T> f){}
static void barz(Action<int> f) { }
static void test()
{
Action<int> f = foo;
bar(f);
barz(foo);
bar(foo);
//these help the compiler to know which types to use
bar<int>(foo);
bar( (int i) => foo(i));
}
}
Foo는 행동이 아닙니다 - Foo는 방법 그룹입니다.
- 할당 문에서 int 유형이 지정되어 있으므로 컴파일러는 어떤 FOO에 대해 말하는 FOO를 명확하게 알 수 있습니다.
- Barz (FOO) 문서에서 int 유형이 지정되어 있으므로 컴파일러는 어떤 FOO에 대해 말하는 FOO를 알 수 있습니다.
- BAR (FOO) 문서에서 단일 매개 변수가있는 FOO 일 수 있으므로 컴파일러가 포기할 수 있습니다.
편집 : 컴파일러가 유형을 파악하는 데 도움이되는 두 가지 (예 : 추론 단계를 건너 뛰는 방법)를 추가했습니다.
JSKEET의 답변에있는 기사를 읽은 후 유형을 추론하지 않기로 한 결정은 상호 추론 시나리오를 기반으로하는 것 같습니다.
static void foo<T>(T x) { }
static void bar<T>(Action<T> f) { }
static void test()
{
bar(foo); //wut's T?
}
일반적인 문제는 해결할 수 없었기 때문에 해결책이 해결되지 않은 특정 문제를 남기도록 선택합니다.
이 결정의 결과로, 당신은 방법에 대한 과부하를 추가하고 단일 멤버 메소드 그룹에 사용되는 모든 발신자로부터 많은 유형의 혼란을 얻지 못합니다. 좋은 일인 것 같아요.
다른 팁
추론은 유형이 확장되면 실패의 가능성이 없어야한다는 것입니다. 즉, 메소드 foo (문자열)가 유형에 추가되면 기존 메소드의 내용이 변경되지 않는 한 기존 코드에 중요하지 않습니다.
이러한 이유로 FOO가 하나만 있더라도 FOO (메소드 그룹이라고도 함)에 대한 참조는 유형이 아닌 대의원에게 캐스트 할 수 없습니다. Action<T>
그러나 다음과 같은 유형 별 대의원에만 Action<int>
.
그것은 약간 이상합니다. 유형 추론에 대한 C# 3.0 사양은 읽기 어렵고 실수가 있지만 외모 작동해야합니다. 첫 번째 단계 (섹션 7.4.2.1)에서는 실수가 있다고 생각합니다. 첫 번째 총알에 메소드 그룹을 언급해서는 안됩니다 (명시 적 매개 변수 단용 추론 (7.4.2.7)으로 덮여 있지 않으므로 사용해야합니다. 출력 단용 추론 (7.4.2.6) 외모 그것이 작동하는 것처럼 - 그러나 분명히 그것은 그렇지 않습니다 :(
MS가 유형 추론의 사양을 개선하려고한다는 것을 알고 있으므로 조금 더 명확해질 수 있습니다. 또한 읽기가 어렵다는 점에 관계없이 메소드 그룹과 유형 추론에 제한이 있다는 것을 알고 있습니다. 방법 그룹이 실제로 단일 메소드 일 때 특수 사용될 수있는 제한 사항이 있습니다.
Eric Lippert에는 블로그 항목이 있습니다 방법 그룹과 함께 작동하지 않는 반환 단위 추론 그게 비슷한 이 경우 - 그러나 여기서 우리는 매개 변수 유형에만 리턴 유형에 관심이 없습니다. 가능합니다 그의 유형 추론 시리즈의 다른 게시물 그래도 도움이 될 수 있습니다.
임무를 명심하십시오
Action<int> f = foo;
이미 구문 설탕이 많이 있습니다. 컴파일러는 실제로이 명령문에 대한 코드를 생성합니다.
Action<int> f = new Action<int>(foo);
해당 메소드 호출은 문제없이 컴파일됩니다.
bar(new Action<int>(foo));
FWIW, 컴파일러가 유형 인수를 추론하는 데 도움이됩니다.
bar<int>(foo);
그래서 그것은 과제 진술서의 설탕이 왜 통화되지 않았는가? 설탕이 과제에 명백하지 않기 때문에 하나의 가능한 대체만이 있습니다. 그러나 메소드 호출의 경우 컴파일러 작성자는 이미 과부하 해상도 문제를 처리해야했습니다. 그 규칙은 매우 정교합니다. 그들은 아마 그것에 도달하지 않았을 것입니다.
완전성을 위해서는 C#에만 국한되지 않습니다. 동일한 vb.net 코드도 비슷하게 실패합니다.
Imports System
Module Test
Sub foo(ByVal x As integer)
End Sub
Sub bar(Of T)(ByVal f As Action(Of T))
End Sub
Sub Main()
Dim f As Action(Of integer) = AddressOf foo ' I can do this
bar(f) ' and then do this
bar(AddressOf foo) ' but this does not work
End Sub
End Module
오류 BC32050 : 'public sub bar (t) (fs System.action (t))'에 대한 파라미터 't'유형을 추론 할 수 없습니다.