[C#] 익명 메소드를 var에 할당 할 수없는 이유는 무엇입니까?

다음 코드가 있습니다.

Func<string, bool> comparer = delegate(string value) {
    return value != "0";
};

그러나 다음은 컴파일되지 않습니다.

var comparer = delegate(string value) {
    return value != "0";
};

컴파일러가 왜 그것을 알 수 Func<string, bool>없습니까? 하나의 문자열 매개 변수를 사용하고 부울을 반환합니다. 대신 오류가 발생합니다.

암시 적으로 형식화 된 로컬 변수에 익명 메서드를 할당 할 수 없습니다.

나는 하나의 추측을 가지고 있으며 var 버전이 컴파일 된 경우 다음과 같은 경우 일관성이 부족합니다.

var comparer = delegate(string arg1, string arg2, string arg3, string arg4, string arg5) {
    return false;
};

Func <>은 최대 4 개의 인수 (.NET 3.5에서는 사용중인 것) 만 허용하므로 위의 내용은 의미가 없습니다. 아마도 누군가가 문제를 분명히 할 수있을 것입니다. 감사.



답변

다른 사람들은 이미 의미 할 있는 가능한 많은 델리게이트 유형이 있다고 지적했습니다. 너무 특별 Func해서 Predicate또는 대신에 기본값이 될 가치가있는 것Action 또는 다른 가능성은? 그리고 람다의 경우 표현 트리 형식이 아닌 대리자 형식을 선택하려는 의도가 분명한 이유는 무엇입니까?

그러나 우리는 이것이 Func특별 하다고 말할 수 있으며 유추 된 람다 또는 익명의 방법은 Func의 무언가 라고 말할 수 있습니다. 우리는 여전히 모든 종류의 문제가 있습니다. 다음과 같은 경우 어떤 유형의 유추를 원하십니까?

var x1 = (ref int y)=>123;

Func<T>아무 것도 참조하는 유형 이 없습니다 .

var x2 = y=>123;

리턴 값은 알고 있지만 형식 매개 변수의 유형은 모릅니다. (또는 우리는? 반환은 int? long? short? 바이트입니까?)

var x3 = (int y)=>null;

반품 유형은 알 수 없지만 무효화 할 수는 없습니다. 리턴 유형은 모든 참조 유형 또는 널 입력 가능 값 유형일 수 있습니다.

var x4 = (int y)=>{ throw new Exception(); }

다시, 우리는 리턴 타입을 모른다. 그리고 이번에는 그것이 무효 있다.

var x5 = (int y)=> q += y;

그것은 void-returning statement lambda 또는 q에 할당 된 값을 반환하는 것입니까? 둘 다 합법적입니다. 우리는 어느 것을 선택해야합니까?

자, 당신은 그 기능들을 지원하지 않는다고 말할 것입니다. 유형을 해결할 수있는 “일반적인”경우 만 지원하십시오. 도움이되지 않습니다. 어떻게하면 내 인생이 더 쉬워 집니까? 이 기능이 가끔 작동하고 가끔 실패하는 경우에도 이러한 모든 실패 상황 을 감지 하고 각각에 대해 의미있는 오류 메시지표시 하는 코드를 작성해야합니다 . 우리는 여전히 모든 행동을 명시하고, 문서화하고, 테스트를 작성해야합니다. 이것은 매우 비싼 기능입니다 은 사용자가 약 6 번의 키 입력을 줄일 수 입니다. 우리는 절반의 시간 동안 작동하지 않고 작동하는 경우 거의 이점을 제공하지 않는 기능에 대해 테스트 케이스를 작성하는 데 많은 시간을 소비하는 것보다 언어에 가치를 더하는 더 좋은 방법이 있습니다.

실제로 유용한 상황은 다음과 같습니다.

var xAnon = (int y)=>new { Y = y };

해당 “말할 수있는”유형이 없기 때문입니다. 그러나 우리는 항상이 문제가 있으며 유형을 추론하기 위해 메소드 유형 유추를 사용합니다.

Func<A, R> WorkItOut<A, R>(Func<A, R> f) { return f; }
...
var xAnon = WorkItOut((int y)=>new { Y = y });

그리고 이제 메소드 타입 추론은 func 타입이 무엇인지 알아냅니다.


답변

Eric Lippert만이 확실하게 알고 있지만 위임 유형의 서명이 유형을 고유하게 결정하지 않기 때문이라고 생각합니다.

귀하의 예를 고려하십시오.

var comparer = delegate(string value) { return value != "0"; };

여기에 대한 두 가지 가능한 추론이 있습니다. var 이 있습니다.

Predicate<string> comparer  = delegate(string value) { return value != "0"; };  // okay
Func<string, bool> comparer = delegate(string value) { return value != "0"; };  // also okay

컴파일러는 어느 것을 추론해야합니까? 둘 중 하나를 선택해야 할 이유가 없습니다. 그리고 a Predicate<T>는 기능적으로 a와 동일 하지만 Func<T, bool>.NET 유형 시스템 수준에서 여전히 다른 유형입니다. 따라서 컴파일러는 대리자 형식을 명확하게 확인할 수 없으므로 형식 유추에 실패해야합니다.


답변

에릭 Lippert의 오래된이 그는 말한다 곳에 약을

실제로 C # 2.0 사양에서는이를 호출합니다. 메소드 그룹 표현식 및 익명 메소드 표현식은 C # 2.0에서 유형이없는 표현식이며 람다 표현식은 C # 3.0에서이를 결합합니다. 그러므로 그들이 암묵적 선언의 오른쪽에 “나체”로 나타나는 것은 불법입니다.


답변

다른 대표는 다른 유형으로 간주됩니다. 예를 들어, Action와 다르고 MethodInvoker의 인스턴스 Action를 유형의 변수에 할당 할 수 없습니다 MethodInvoker.

그래서, 익명의 대표 (또는 람다) 등의 주어진 () => {}, 그것에게 인 Action또는를 MethodInvoker? 컴파일러가 말할 수 없습니다.

마찬가지로, string인수를 받아서를 반환 하는 대리자 형식을 선언 bool하면 컴파일러 Func<string, bool>가 내 대리자 형식 대신 실제로 원하는 것을 어떻게 알 수 있습니까? 델리게이트 유형을 유추 할 수 없습니다.


답변

다음은 암시 적으로 형식이 지정된 로컬 변수에 관한 MSDN의 요점입니다.

  1. var는 로컬 변수가 동일한 명령문에서 선언되고 초기화 될 때만 사용할 수 있습니다. 변수는 널 또는 메소드 그룹 또는 익명 함수로 초기화 될 수 없습니다.
  2. var 키워드는 컴파일러에게 초기화 명령문의 오른쪽에있는 표현식에서 변수 유형을 유추하도록 지시합니다.
  3. var 키워드는 “variant”를 의미하지 않으며 변수가 느슨하게 입력되었거나 늦게 묶여 있음을 나타내지 않습니다. 단지 컴파일러가 가장 적합한 유형을 결정하고 할당한다는 의미입니다.

MSDN 참조 : 암시 적으로 형식이 지정된 로컬 변수

익명 방법에 대해 다음을 고려하십시오.

  1. 익명 메소드를 사용하면 매개 변수 목록을 생략 할 수 있습니다.

MSDN 참조 : 익명 방법

익명 메소드에는 실제로 다른 메소드 서명이있을 수 있으므로 컴파일러는 할당 할 가장 적합한 유형을 올바르게 추론 할 수 없습니다.


답변

내 게시물은 실제 질문에 대답하지 않지만 다음과 같은 근본적인 질문에 대답합니다.

“어떻게 애매 모호한 유형을 입력하지 않아도 Func<string, string, int, CustomInputType, bool, ReturnType>되는가?”[1]

내가 게으른 / 해킹 프로그래머이기 때문에 나는 Func<dynamic, object> -단일 입력 매개 변수를 사용하고 객체를 반환하는-를 .

여러 인수에 대해 다음과 같이 사용할 수 있습니다.

dynamic myParams = new ExpandoObject();
myParams.arg0 = "whatever";
myParams.arg1 = 3;
Func<dynamic, object> y = (dynObj) =>
{
    return dynObj.arg0.ToUpper() + (dynObj.arg1 * 45); //screw type casting, amirite?
};
Console.WriteLine(y(myParams));

팁 : 사용할 수 있습니다 Action<dynamic> 객체를 반환 할 필요가없는 경우 .

네, 아마도 프로그래밍 원칙에 위배된다는 것을 알고 있습니다.

나는 대의원에서 초심자입니다 … 내가 배운 것을 나누고 싶었습니다.


[1] 이것은 미리 정의 된 Func매개 변수 를 요구하는 메서드를 호출하지 않는 것으로 가정합니다 . 이 경우 해당 문자열을 입력해야합니다.


답변

어때요?

var item = new
    {
        toolisn = 100,
        LangId = "ENG",
        toolPath = (Func<int, string, string>) delegate(int toolisn, string LangId)
        {
              var path = "/Content/Tool_" + toolisn + "_" + LangId + "/story.html";
              return File.Exists(Server.MapPath(path)) ? "<a style=\"vertical-align:super\" href=\"" + path + "\" target=\"_blank\">execute example</a> " : "";
        }
};

string result = item.toolPath(item.toolisn, item.LangId);