이 사례를 이해하지 못합니다.
public delegate int test(int i);
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
public test Fail()
{
Func<int, int> f = x => x;
return f; // <- code doesn't compile
}
왜 Invoke
메소드를 사용할 때 컴파일이 OK 이고 csharp Func<int,int>
직접 리턴 할 때 OK가 아닌가?
답변
이 동작을 이해하기 위해 알아야 할 두 가지가 있습니다.
- 모든 델리게이트는에서 파생
System.Delegate
되지만 다른 델리게이트는 유형이 다르므로 서로를 할당 할 수 없습니다. - C # 언어 는 메서드 나 람다를 대리자에게 할당하기위한 특수 처리 기능을 제공합니다 .
다른 델리게이트의 유형이 다르므로 한 유형의 델리게이트를 다른 유형에 지정할 수 없습니다.
예를 들면 다음과 같습니다.
delegate void test1(int i);
delegate void test2(int i);
그때:
test1 a = Console.WriteLine; // Using special delegate initialisation handling.
test2 b = a; // Using normal assignment, therefore does not compile.
위의 첫 번째 줄은 람다 또는 메서드를 대리자에 할당하기 위해 특수 처리를 사용하므로 OK를 컴파일합니다.
실제로이 줄은 컴파일러에 의해 다음과 같이 효과적으로 다시 작성됩니다.
test1 a = new test1(Console.WriteLine);
위의 두 번째 줄은 한 유형의 인스턴스를 다른 호환되지 않는 유형에 할당하려고하기 때문에 컴파일되지 않습니다.
지금까지 유형에 갈 때, 사이의 대입 호환성이없는 test1
및 test2
서로 다른 종류 때문에이.
생각하는 데 도움이된다면이 클래스 계층 구조를 고려하십시오.
class Base
{
}
class Test1 : Base
{
}
class Test2 : Base
{
}
다음 코드는 컴파일, 비록되지 않습니다 Test1
와 Test2
같은 기본 클래스에서 파생 :
Test1 test1 = new Test1();
Test2 test2 = test1; // Compile error.
이것은 한 델리게이트 유형을 다른 델리게이트 유형에 할당 할 수없는 이유를 설명합니다. 그것은 단지 일반적인 C # 언어입니다.
그러나 중요한 것은 왜 메서드 나 람다를 호환 가능한 대리자에게 할당 할 수 있는지 이해하는 것입니다. 위에서 언급했듯이 이는 델리게이트에 대한 C # 언어 지원의 일부입니다.
마지막으로 귀하의 질문에 대답하십시오.
사용할 때 Invoke()
호환되지 않는 형식을 할당하지 않고 메서드 또는 람다를 대리자에 할당하기 위해 특수 C # 언어 처리를 사용하여 대리자에 METHOD 호출을 할당하므로 확인이 컴파일됩니다.
OP에서 컴파일하는 코드는 완전히 명확하게합니다.
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
실제로 개념적으로 다음과 같은 것으로 변환됩니다.
public test Success()
{
Func<int, int> f = x => x;
return new test(f.Invoke);
}
실패한 코드는 호환되지 않는 두 가지 유형 사이에 할당하려고 시도합니다.
public test Fail()
{
Func<int, int> f = x => x;
return f; // Attempting to assign one delegate type to another: Fails
}
답변
두 번째 경우 f
는 유형 Func<int, int>
이지만 메소드는를 반환한다고합니다 test
. 이들은 서로 관련이없는 관련 (위임) 유형이므로 서로 컴파일러 오류가 발생합니다. 언어 사양 의이 섹션 으로 이동하여 “대리인”을 검색 할 수 있습니다 . 동일한 서명을 가진 델리게이트 간의 변환에 대한 언급은 없습니다.
그러나 전자의 경우, f.Invoke
A는 메소드 그룹 식 실제로 입력이없는. C # 컴파일러는 메소드 그룹 변환을 통해 컨텍스트에 따라 메소드 그룹 표현식을 특정 델리게이트 유형으로 변환 합니다.
( 여기 에서 다섯 번째 글 머리표 인용, 내 것을 강조)
식은 다음 중 하나로 분류됩니다.
…
멤버 조회로 인한 오버로드 된 메소드 세트 인 메소드 그룹. […] 메소드 그룹은 invocation_expression, delegate_creation_expression 및
is
연산자 의 왼쪽으로 허용되며 암시 적으로 호환 가능한 대리자 유형으로 변환 될 수 있습니다.
이 경우 test
대리자 유형으로 변환됩니다 .
즉, 이미 유형이 있지만 아직 유형이 return f
없기 때문에 작동 하지 않습니다.f
f.Invoke
답변
여기서 문제는 유형 호환성입니다.
다음은 MSDN 소스 의 Func 델리게이트 정의입니다 .
public delegate TResult Func<in T, out TResult>(T arg);
위에서 언급 한 Func과 정의 된 델리게이트간에 직접적인 관계가없는 경우 :
public delegate int test(int i);
첫 번째 스 니펫이 컴파일되는 이유 :
public test Success()
{
Func<int, int> f = x => x;
return f.Invoke; // <- code successfully compiled
}
델리게이트는 입력 매개 변수 및 출력 결과 인 서명을 사용하여 비교되며, 궁극적으로 델리게이트는 함수 포인터이며 두 함수는 서명을 통해서만 비교할 수 있습니다. 런타임시 Func를 통해 호출 된 메소드는 Test
대리자 에게 할당됩니다. Signature는 동일하므로 원활하게 작동합니다. 함수 포인터 할당입니다. Test
델리게이트가 이제 Func 델리게이트가 가리키는 메소드를 호출합니다.
2 차 스 니펫이 컴파일되지 않는 이유
Func와 테스트 대리자 사이에는 형식 / 할당 호환성이 없으며 Func은 형식 시스템 규칙의 일부로 채울 수 없습니다. test delegate
첫 번째 경우 와 같이 결과를 할당하고 채울 수있는 경우에도 마찬가지입니다.