为什么在Func和Expression <Func>之间lambda表达式参数不明确?

Jef*_*Sax 23 .net lambda expression-trees

假设我有一个班级:

class MyClass {
    public int MyMethod(Func<int, int> f) { return 0; }
    public int MyMethod(Expression<Func<int, int>> f) { return 1; }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试使用lambda表达式调用该方法时,我收到一个编译错误,指出调用在两个重载之间是不明确的:

var myClass = new MyClass();
myClass.MyMethod(x => 1 + x); // Error!
Run Code Online (Sandbox Code Playgroud)

当然,使用显式类型调用可以正常工作:

myClass.MyMethod((Func<int, int>)(x => 1 + x)); // OK, returns 0
myClass.MyMethod((Expression<Func<int, int>>)(x => 1 + x)); // OK, returns 1
Run Code Online (Sandbox Code Playgroud)

表达式树包含更多信息(实际代码),我可能希望在可用时使用此信息.但我也希望我的代码能够与代表合作.不幸的是,这种模糊性使得我必须找到另一种方法来区分两个调用,这会混淆一个干净的API.

C#规范没有说明这个具体情况,所以在这个意义上,行为确实符合规范.

但是,有一个论点要求表达式树应该优先于委托.该Compile方法充当从表达式树到委托的显式转换.表达式树包含更多信息,当您编译为委托时,您将丢失该信息.另一方面没有转换.

有没有理由不喜欢表达树?

Joã*_*elo 6

回答关于标题的问题,它们是模棱两可的,因为类型系统没有"lambda表达"的概念.它是一个编译器功能,可以转换为委托或表达式树,因此您需要明确要转换它的类型.大多数情况下,编译器会自动推断目标,因为使用lambda表达式的上下文.例如,在IEnumerable扩展方法中使用lambdas与在扩展方法中使用lambda IQueryable.

现在,为了回答关于为什么不总是更喜欢表达式树的问题,你有MagnatLU已经说过的性能参数.如果您接受a Expression然后调用Compile才能执行它,那么与接受委托相比,它总是会变慢.

两者之间也存在语义差异,委托只是执行某些代码的一种方式,而表达式树是实际代码的描述.

如果我是你,我会选择将接受表达式的方法的名称更改为明确反映基于委托的额外内容的方法.