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

C#编译器用于解析lambda表达式中的类型的规则是什么?,c#,C#,关于,我理解C#中不支持以下内容: 但是,我可以创建一个方法,Func,其形式如下: public static Func<T,T,T> Func<T>(Func<T,T,T> f) => f; 这也将被编译。因此,C#编译器似乎能够推断lambda的返回类型。但是,以下内容无法编译: var func = Func((x,y) => Math.Log(x) + Math.Log(y)); 因为编译器似乎无法从正文中使用的方式推断x和y的类型

关于,我理解C#中不支持以下内容:

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

public static Func<T,T,T> Func<T>(Func<T,T,T> f) => f;
这也将被编译。因此,C#编译器似乎能够推断lambda的返回类型。但是,以下内容无法编译:

var func = Func((x,y) => Math.Log(x) + Math.Log(y));
因为编译器似乎无法从正文中使用的方式推断
x
y
的类型


那么,我的问题是:关于lambda表达式的类型推断的确定规则是什么;编译器会推断出什么,它不会推断出什么

您必须提供所有参数和结果的类型,或者:

  • 显式地,通过在通用尖括号(
    )之间或lambda参数列表中声明它(例如:
    (int a,int b)=>{/*…*/}
  • 隐式地,在编译器可以推断结果类型的情况下,推断
    var
    类型的方式相同

  • 之所以编译,是因为这里提供的类型是
    double

    public static Func<T,T,T> Func<T>(Func<T,T,T> f) => f;
    var func = Func<double>((x,y) => Math.Log(x) + Math.Log(y));
    
  • 但是,这不会编译,因为
    T1
    T2
    的类型未知。编译器无法改变它们的类型的使用方式

    public static Func<T1,T2,T3> Func<T1,T2,T3>(Func<T1,T2,T3> f) => f;
    var func = Func((x,y) => Math.Log(x) + Math.Log(y));
    
    公共静态函数Func(Func f)=>f;
    var func=func((x,y)=>Math.Log(x)+Math.Log(y));
    
lambda表达式类型推断的确定规则是什么

规范中有明确的规则。如果您想查看实现,可以在Roslyn源代码中轻松找到它;我对此评论得很重,预计会有问题。请注意,尤其是从第110行开始的评论与您的问题相关;如果您想深入了解lambda类型推断的工作原理,请仔细研究这一点

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

编译器会推断出什么,它不会推断出什么

这是一个过于宽泛的问题,无法给出明确的答案。但关于你问题中的例子,基本行动是:

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

我录制了一段视频——十年前的现在——一步一步地解释所有这些,但显然它已经不在MSDN上了。我很烦恼

我同意现在已经放弃的答案。。只需要阅读指定的参考资料,就可以知道c#匿名类型推理的确切规则,而且我承认我没有必要的知识来说明这个问题有多广泛,但我相信,我相信世卫组织说这是一个非常广泛的问题

然而,我本以为,如果规则是明确的,那么编译器应该工作,因为某些类型的推理规则是逻辑的,而不是任意的

在您的示例中,无法执行最后一次计算,因为每个参数的类型可以是“double”类型或其他兼容类型之外的所有类型,这是正确的。但是相反,如果你编写了lambda表达式,这样就不可能在返回类型函数的推理中出错,那么,我希望它能工作,而不是不工作

例如,下面的代码,我希望它可以工作,但不能:

public static Func<T1, T2, T3> Func<T1, T2, T3>(Func<T1, T2, T3> f) => f;
var func = Func((x, y) => string.Format("{0},{1}", x.ToString(), y.ToString()));
所以,在我看来,编译器完全避免进行任何类型的推理。当它是安全的,然后它执行计算,否则就不会


我希望我回答了你的问题,或者至少给出了一个有用的指示或跟踪。

我投票决定结束,因为C#spec中包含的类型推断太宽泛了。如果你问为什么你的特定代码无法编译,那是一回事,但要求所有类型推断规则都太宽泛了。@DStanley,规范中的何处?
var func=func((双x,双y)=>$“{x+y}”)-这不是在推断什么。它接受两个double并输出一个字符串,因此它的类型为
Func
@DavidArno 7.5.2类型推断,因为它无法推断
x
y
的类型,因为它将编译多个类型。它不会为你选择一个。对于其他示例,参数没有类型推断,因为您明确地说类型是
double
Perfect。谢谢Eric,可惜你的视频不见了;这听起来很值得一看。
var func = Func((x,y) => Math.Log(x) + Math.Log(y));
public static Func<T,T,T> Func<T>(Func<T,T,T> f) => f;
var func = Func<double>((x,y) => Math.Log(x) + Math.Log(y));
public static Func<T1,T2,T3> Func<T1,T2,T3>(Func<T1,T2,T3> f) => f;
var func = Func((double x, double y) => $"{x + y}");
public static Func<T1,T2,T3> Func<T1,T2,T3>(Func<T1,T2,T3> f) => f;
var func = Func((x,y) => Math.Log(x) + Math.Log(y));
public static Func<T1, T2, T3> Func<T1, T2, T3>(Func<T1, T2, T3> f) => f;
var func = Func((x, y) => string.Format("{0},{1}", x.ToString(), y.ToString()));
double x1 = 0, y1 = 0;
var func = Func((x, y) => Math.Log(double.TryParse(x.ToString(),x1)) + Math.Log(double.TryParse(y.ToString(), y1)));