C#编译器用于解析lambda表达式中的类型的规则是什么?

Dav*_*rno 3 c#

参考为什么不能将匿名方法分配给var?,我知道C#不支持以下内容:

var func = (x,y) => Math.Log(x) + Math.Log(y);
Run Code Online (Sandbox Code Playgroud)

但是,我可以创建一个方法,Func形式如下:

public static Func<T,T,T> Func<T>(Func<T,T,T> f) => f;
Run Code Online (Sandbox Code Playgroud)

然后做:

var func = Func<double>((x,y) => Math.Log(x) + Math.Log(y));
Run Code Online (Sandbox Code Playgroud)

那将编译得很好.但是,对于参数和返回值具有不同类型的lambda,事情变得奇怪.例如,如果我有一个方法:

public static Func<T1,T2,T3> Func<T1,T2,T3>(Func<T1,T2,T3> f) => f;
Run Code Online (Sandbox Code Playgroud)

我可以这样做:

var func = Func((double x, double y) => $"{x + y}");
Run Code Online (Sandbox Code Playgroud)

那也将编译.所以C#编译器似乎能够推断出lambda的返回类型.但是,以下内容将无法编译:

var func = Func((x,y) => Math.Log(x) + Math.Log(y));
Run Code Online (Sandbox Code Playgroud)

因为编译器似乎无法推断它们在体内使用的方式x和类型y.

所以,我的问题是:关于lambda表达式类型推断的明确规则是什么; 编译器将推断出什么,不会推断出什么?

Eri*_*ert 6

关于lambda表达式类型推断的明确规则是什么?

明确的规则是规范.如果您想查看实现,可以在Roslyn源代码中轻松找到它; 我非常评价它,期待会有问题.请注意,特别是从第110行开始的评论与您的​​问题相关; 如果您想深入了解lambda类型推断是如何工作的,请仔细研究这一点.

https://github.com/dotnet/roslyn/blob/master/src/Compilers/CSharp/Portable/Binder/Semantics/OverloadResolution/MethodTypeInference.cs

考虑在调试模式下自己编译编译器; 然后,您可以Dump在断点处使用该方法来描述类型推理引擎的状态.我用它来促进更快速的调试,并考虑扩展算法.(其中一些仍然在代码中,注释掉了.)

编译器将推断出什么,不会推断出什么?

这是一个过于宽泛的问题,无法明确回答.但是关于你问题中的例子的基本动作是:

  • 类型参数的界限是从与形式参数类型匹配的普通参数推断出来的.
  • 推断或已知lambda的所有形式参数类型的Lambdas都推断出它们的返回类型
  • 重复上一步骤,直到算法无法取得进展或推断出矛盾.

我录制了一段视频 - 十年前的现在 - 一步一步解释所有这些,但显然已经不再是在MSDN上了.我很烦.