Lambda表达式常见语法

4

我可以遵循一些简单的语法或规则来构建 C# 中的“Lambda 表达式”吗?我读了一些文章并理解了什么是 Lambda 表达式,但如果我有通用的语法或规则,那将会很有帮助。

2个回答

10

有多种表达Lambda表达式的方式,具体取决于情境 - 以下是一些示例:

    // simplest form; no types, no brackets
    Func<int, int> f1 = x => 2 * x;
    // optional exlicit argument brackets
    Func<int, int> f2 = (x) => 2 * x;
    // optional type specification when used with brackets
    Func<int, int> f3 = (int x) => 2 * x;
    // multiple arguments require brackets (types optional)
    Func<int, int, int> f4 = (x, y) => x * y;
    // multiple argument with explicit types
    Func<int, int, int> f5 = (int x, int y) => x * y;

这个lambda表达式的签名必须与使用的委托的签名匹配(无论是像上面那样明确指定还是在像 .Select(cust => cust.Name) 中隐含的上下文中指定)

您可以通过使用空表达式列表来使用没有参数的lambda表达式:

    // no arguments
    Func<int> f0 = () => 12;

理想情况下,右侧的表达式应该只是一个单一的表达式。编译器可以将其转换为 任意一个 delegate 或者 Expression 树形结构:

    // expression tree
    Expression<Func<int, int, int>> f6 = (x, y) => x * y;

然而,你也可以使用语句块,但这只能作为一个delegate来使用:

    // braces for a statement body
    Func<int, int, int> f7 = (x, y) => {
        int z = x * y;
        Console.WriteLine(z);
        return z;
    };

请注意,尽管.NET 4.0的Expression树支持语句体,但C# 4.0编译器不会为您执行此操作,因此您仍然仅限于简单的Expression树,除非您使用“困难的方式”进行操作;有关更多信息,请参见我的InfoQ文章


8

一个lambda表达式,本质上是一个函数指针的简写表示法。更常见的情况是,lambda表达式将输入数据传递到计算结果的表达式中。在大多数情况下,您将使用lambda表达式的常见形式:

int[] numbers = new[] { 1, 3, 11, 21, 9, 23, 7, 4, 18, 7, 7, 3, 21 };

var twentyoneCount = numbers.Where(n => n == 21).Count();
var sumOfgreaterThanSeven = numbers.Sum(n => n > 7 ? n : 0);

在它们不太常见的形式中,Lambda表达式可以替换更加笨重的委托形式:

myButton.Click += new EventHandler(myButton_Click);
// ...
void myButton_Click(object sender, EventArgs e)
{
    // TODO: Implement button click handler here
}

或者更少见、更简洁的写法:
myButton.Click += delegate(object sender, EventArgs e)
{
    // TODO: Implement button click handler here
};

下面的lambda表达式可以达到与上面两个相同的结果:
myButton.Click += (s,e) =>
{
    // TODO: Implement button click handler here
};

这种形式的真正优势在于它能够创建闭包。闭包是指在函数内部实现另一个函数,并且从父函数作用域中“封闭”参数和变量:
private void DoSomething(IList<string> input, SomeObject source)
{
    source.OnSomeEvent += (s,e) => return input.Sum();
}

太好了。这确实让我接触到了真正的编程世界。万分感谢jrista。 - user184805
"Lambda表达式本质上是函数指针的简写符号。然而,重要的区别和关键特征在于lambda能够被视为数据(表达式树),而不是代码(匿名方法)。" https://dev59.com/0XRA5IYBdhLWcg3w4SDo#793584 - Mehrdad Afshari
@Mehrdad:没错,Lambda表达式最初确实会变成表达式树。但是,评估表达式树的最终结果是评估动态方法,该方法由委托指向。表达式树只是最终函数指针的中间表示。请注意.Compile()方法,它返回一个委托:http://msdn.microsoft.com/en-us/library/bb345362.aspx - jrista
jrista:但是没有人强制你在表达式树上调用.Compile()。典型的例子是LINQ to SQL。它不会在你的表达式树上调用编译器,最终结果也不是一个函数,而是生成的SQL语句。 - Mehrdad Afshari
Mehrdad:好观点。就像L2S这样的情况,你绝对是正确的,它们在全部时行为表达式树。 - jrista

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接