T of Func<S, T> is inferred from output of lambda expression only when S and T are different?

ε祈祈猫儿з 提交于 2019-12-10 03:19:33

问题


When S and T are different, this works:

public static void Fun<S, T>(Func<S, T> func)
{

}

Fun((string s) => true); //compiles, T is inferred from return type.

But,

public static void Fun<T>(Func<T, T> func)
{

}

Fun(t => true); //can't infer type.

In the first example, since T is inferred from return type of lambda expression, can't T in the second example too be inferred? I suppose its doing it, but why is first T not known, when second T of Func<T, T> is known, after all T == T right? Or is there an order for types being inferred in case of Funcs?


回答1:


It has nothing whatsoever to do with S and T being different. It has to do with you supplying the formal parameter type in the first case and not supplying it in the second case.

Method type inference does not attempt to infer the return type of a delegate from a lambda until the formal parameter types of the delegate are known.

In the second case you've given the compiler nothing with which to infer the formal parameter type T, and therefore the body of the lambda will not even be analyzed.

What do you mean by "formal parameter type"?

A formal parameter is a variable that takes on the value of an argument passed to a method, indexer, constructor, lambda or anonymous method. (Or, in the case of out and ref formal parameters, becomes an alias to a variable supplied by the caller.) Formal parameters are variables, and therefore have types.

The delegate delegate R Func<A, R>(A a); has formal parameter a with type A. You construct that with method type parameters to make Func<S, T>, so the formal parameter type of the delegate is now S. The task of type inference is to infer those types S and T.

In your first example you have a lambda with formal parameter s of type string. So type inference reasons that since this lambda argument corresponds to formal parameter func of method Fun, and the formal parameter type of func is Func<S, T> then the formal parameter type of s must correspond to S. Since you gave a formal parameter type for s, S is inferred to be string.

Once that inference is made then T can be inferred by analyzing the body of the lambda.

In your second case, there is no formal parameter type given for t. Since there is nothing else from which the type of t can be deduced, type inference gives up and abandons analyzing this lambda before looking at the body.

It just so happens that in your case the body could be analyzed independently of the formal parameter type of the lambda. That is a rare case and the type inference algorithm was not written to take advantage of it.

If this is the sort of type inference you want, consider using F# instead of C#. It has a far more advanced type inference algorithm, based on the Hindley-Milner algorithm.




回答2:


Generic parameters for lambdas and other functions are determined by their parameter types, not their return type. It's exactly the same reason why you cannot do this:

T Foo<T>() { return default(T); }

string x = Foo(); // error

For the expression t => true, we clearly don't know what t could possibly be so the compiler cannot make any more decisions based on this alone.



来源:https://stackoverflow.com/questions/14837286/t-of-funcs-t-is-inferred-from-output-of-lambda-expression-only-when-s-and-t-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!