其他答案忽略了 lambda 表达式不一定代表方法的事实。有时,它们代表表达式树。
编译器根据上下文将 lambda 表达式隐式转换为一种或另一种类型的对象。
要指定方法,您需要指定参数和主体。在 lambda 表达式中,它们由 . 分隔=>
。例子:
() => 4; //empty parameter list
x => x.ToString(); //one parameter
(a, b) => a.Equals(b); //two parameters
// ^^^^^^ ^^^^^^^^^^^^
// | |
// parameter list body
这些 lambda 表达式可以分别转换为Func<int>
、Func<object, string>
和Func<object, object, bool>
。也可以分别转换为Expression<Func<int>>
、Expression<Func<object, string>>
和Expression<Func<object, object, bool>>
。
匿名方法:
delegate (object p, object q) { return string.Concat(p, q); }
// ^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// parameter list body
以下是 lambda 转换的两个示例:
Func<object, object, bool> aDelegate = (o1, o2) => object.Equals(o1, o2);
Expression<Func<object, object, bool>> anExpressionTree = (o1, o2) => object.Equals(o1, o2);
在方法组转换中,参数和方法体由重载决议指定。为了简化一点,编译器查看具有指定名称的方法并根据上下文选择正确的重载。例如,考虑 SquareMethod 的这些重载:
int SquareMethod(int a) { return a * a; }
double SquareMethod(double a) { return a * a; }
这些语句涉及方法组转换和重载解析:
Func<int, int> squareAnInt = SquareMethod;
Func<double, double> squareADouble = SquareMethod;
最后,语句 lambda 不能转换为表达式树:
Action<object> anAction = o => { Console.WriteLine(o); };
Func<object, int> aFunc = o =>
{
var s = (o ?? "").ToString();
Console.WriteLine(s);
return s.Length;
};
C# 语言规范(有些混乱)使用术语“匿名函数”来涵盖 lambda 表达式和匿名方法。匿名函数可以隐式转换为兼容的委托类型,方法组也可以。因此,如果我们有一个名为 的委托类型DelegateType
,以及这样的声明/赋值:
DelegateType d = [something];
然后[something]
可以是方法组或匿名函数。换句话说,它可以是方法组、匿名方法或 lambda 表达式。
因此,您对本书文字的更正最好说“代替方法组”,但我会说
lambda 表达式是一种未命名的方法,与命名方法组一样,可用于创建委托实例。
我还可以补充
在某些情况下,可以使用 lambda 表达式来创建表达式树而不是委托实例。