C#Lambda表达式:我为什么要使用它们?

时间:2008-10-03 15:11:15

标签: c# c#-3.0 lambda

我已经快速阅读了Microsoft Lambda Expression文档。

这种例子让我更好地理解:

delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25

但是,我不明白为什么这是一项创新。它只是一种在“方法变量”结束时死亡的方法,对吗?我为什么要使用它而不是真正的方法?

15 个答案:

答案 0 :(得分:276)

Lambda expressions是匿名委托的一种更简单的语法,可以在任何地方使用匿名委托。然而,事实恰恰相反; lambda表达式可以转换为表达式树,它允许像LINQ to SQL这样的很多魔法。

以下是使用匿名委托然后使用lambda表达式的LINQ to Objects表达式的示例,以显示它们的容易程度:

// anonymous delegate
var evens = Enumerable
                .Range(1, 100)
                .Where(delegate(int x) { return (x % 2) == 0; })
                .ToList();

// lambda expression
var evens = Enumerable
                .Range(1, 100)
                .Where(x => (x % 2) == 0)
                .ToList();

Lambda表达式和匿名委托比编写单独的函数更有优势:它们实现closures,允许您pass local state to the function without adding parameters到函数或创建一次性使用对象。

Expression trees是C#3.0的一个非常强大的新功能,它允许API查看表达式的结构,而不仅仅是获取对可以执行的方法的引用。 API只需要将委托参数转换为Expression<T>参数,编译器将从lambda而不是匿名委托生成表达式树:

void Example(Predicate<int> aDelegate);

调用如:

Example(x => x > 5);

变为:

void Example(Expression<Predicate<int>> expressionTree);

后者将传递描述表达式x > 5的{​​{3}}的表示。 LINQ to SQL依赖于这种行为,能够将C#表达式转换为服务器端过滤/排序等所需的SQL表达式。

答案 1 :(得分:135)

匿名函数和表达式对于无法从创建完整方法所需的额外工作中受益的一次性方法非常有用。

考虑这个例子:

 string person = people.Find(person => person.Contains("Joe"));

 public string FindPerson(string nameContains, List<string> persons)
 {
     foreach (string person in persons)
         if (person.Contains(nameContains))
             return person;
     return null;
 }

这些在功能上是等效的。

答案 2 :(得分:83)

我发现它们在我想要使用另一个控件为某个控件的事件声明处理程序的情况下很有用。 通常,您必须将控件的引用存储在类的字段中,以便您可以使用与创建它们不同的方法来使用它们。

private ComboBox combo;
private Label label;

public CreateControls()
{
    combo = new ComboBox();
    label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += new EventHandler(combo_SelectedIndexChanged);
}

void combo_SelectedIndexChanged(object sender, EventArgs e)
{
    label.Text = combo.SelectedValue;
}

感谢lambda表达式,你可以像这样使用它:

public CreateControls()
{
    ComboBox combo = new ComboBox();
    Label label = new Label();
    //some initializing code
    combo.SelectedIndexChanged += (s, e) => {label.Text = combo.SelectedValue;};
}

更容易。

答案 3 :(得分:35)

Lambda清理了C#2.0的匿名委托语法...例如

Strings.Find(s => s == "hello");

在C#2.0中完成了这样的事情:

Strings.Find(delegate(String s) { return s == "hello"; });

从功能上讲,它们完全相同,只是一种更简洁的语法。

答案 4 :(得分:29)

这只是使用lambda表达式的一种方法。您可以使用lambda表达式任何地方,您可以使用委托。这允许你做这样的事情:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

strings.Find(s => s == "hello");

此代码将在列表中搜索与单词“hello”匹配的条目。另一种方法是实际将委托传递给Find方法,如下所示:

List<string> strings = new List<string>();
strings.Add("Good");
strings.Add("Morning")
strings.Add("Starshine");
strings.Add("The");
strings.Add("Earth");
strings.Add("says");
strings.Add("hello");

private static bool FindHello(String s)
{
    return s == "hello";
}

strings.Find(FindHello);

修改

在C#2.0中,可以使用匿名委托语法来完成:

  strings.Find(delegate(String s) { return s == "hello"; });

Lambda显着清理了这种语法。

答案 5 :(得分:22)

Microsoft为我们提供了一种更简洁,更方便的方法来创建名为Lambda表达式的匿名委托。但是,对此语句的表达式部分没有太多关注。 Microsoft发布了一个完整的命名空间System.Linq.Expressions,其中包含用于基于lambda表达式创建表达式树的类。表达式树由表示逻辑的对象组成。例如,x = y + z是一个表达式,可能是.Net中表达式树的一部分。考虑以下(简单)示例:

using System;
using System.Linq;
using System.Linq.Expressions;


namespace ExpressionTreeThingy
{
    class Program
    {
        static void Main(string[] args)
        {
            Expression<Func<int, int>> expr = (x) => x + 1; //this is not a delegate, but an object
            var del = expr.Compile(); //compiles the object to a CLR delegate, at runtime
            Console.WriteLine(del(5)); //we are just invoking a delegate at this point
            Console.ReadKey();
        }
    }
}

这个例子很简单。而且我相信你在想,“这是没用的,因为我可以直接创建代理而不是创建表达式并在运行时编译它”。你会是对的。但这为表达树提供了基础。 Expressions名称空间中有许多表达式,您可以构建自己的表达式。我想您可以看到,如果您不确切知道算法在设计或编译时应该是什么,这可能会有用。我在某个地方看到了一个用来编写科学计算器的例子。您也可以将其用于Bayesian系统或genetic programming(AI)。在我的职业生涯中,有几次我不得不编写类似Excel的功能,允许用户输入简单的表达式(加法,减法等)来操作可用数据。在pre-.Net 3.5中,我不得不求助于C#外部的一些脚本语言,或者必须在反射中使用代码发射功能来动态创建.Net代码。现在我会使用表达式树。

答案 6 :(得分:12)

它可以节省必须在特定位置使用一次的方法远离它们使用的位置。良好的用途是作为排序等通用算法的比较器,然后您可以在其中定义一个自定义排序函数,您可以在其中调用排序,而不是进一步强迫您查看其他位置以查看您要排序的内容。

这并不是一项创新。 LISP具有λ功能约30年或更长时间。

答案 7 :(得分:6)

lambda表达式类似于代替委托实例编写的匿名方法。

delegate int MyDelagate (int i);
MyDelagate delSquareFunction = x => x * x;

考虑lambda表达式x => x * x;

  

输入参数值为x(在=&gt;的左侧)

     

函数逻辑是x * x(在=&gt;的右侧)

lambda表达式的代码可以是语句块而不是表达式。

x => {return x * x;};

示例

注意:Func是预定义的通用委托。

    Console.WriteLine(MyMethod(x => "Hi " + x));

    public static string MyMethod(Func<string, string> strategy)
    {
        return strategy("Lijo").ToString();
    }

<强>参考

  1. How can a delegate & interface be used interchangeably?

答案 8 :(得分:6)

您还可以在编写通用代码时使用lambda表达式来处理您的方法。

例如:用于计算方法调用所用时间的通用函数。 (即Action在这里)

public static long Measure(Action action)
{
    Stopwatch sw = new Stopwatch();
    sw.Start();
    action();
    sw.Stop();
    return sw.ElapsedMilliseconds;
}

你可以使用lambda表达式调用上面的方法,如下所示,

var timeTaken = Measure(() => yourMethod(param));

Expression允许您从方法中获取返回值,也可以从param中获取

var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));

答案 9 :(得分:4)

很多时候,你只是在一个地方使用这个功能,所以制作一个方法只会让课堂变得混乱。

答案 10 :(得分:4)

Lambda表达式是一种表示匿名方法的简洁方法。匿名方法和Lambda表达式都允许您内联定义方法实现,但是,匿名方法明确要求您定义方法的参数类型和返回类型。 Lambda表达式使用C#3.0的类型推断功能,允许编译器根据上下文推断变量的类型。它非常方便,因为这样可以节省很多打字!

答案 11 :(得分:3)

这是一种采取小操作并使其非常接近使用位置的方法(与声明接近其使用点的变量不同)。这应该会使您的代码更具可读性。通过对表达式进行匿名化,如果某个人在其他地方使用该函数并对其进行修改以“增强”它,那么您也会更难以破坏客户端代码。

同样,为什么你需要使用foreach?您可以使用plain for循环或直接使用IEnumerable在foreach中执行所有操作。答:你不需要它,但它使你的代码更具可读性。

答案 12 :(得分:0)

创新的类型是安全性和透明度。虽然您没有声明lambda表达式的类型,但它们是推断的,可以由代码搜索,静态分析,重构工具和运行时反射使用。

例如,在您可能使用SQL并且可能获得SQL注入攻击之前,因为黑客传递了一个通常需要数字的字符串。现在你将使用一个LINQ lambda表达式,它受到保护。

在纯委托上构建LINQ API是不可能的,因为它需要在评估它们之前将表达式树组合在一起。

2016年,大多数流行语言都有lambda expression支持,而C#是主流命令式语言在此演变中的先驱之一。

答案 13 :(得分:0)

这可能是为什么要使用lambda表达式的最佳解释 - &gt; https://youtu.be/j9nj5dTo54Q

总之,它是通过重用而不是复制代码来提高代码可读性,减少错误的可能性,并利用幕后发生的优化。

答案 14 :(得分:0)

lambda表达式和匿名函数的最大好处是它们允许库/框架的客户端(程序员)通过给定库/框架中的代码注入功能(因为它是LINQ,ASP)。 NET Core和许多其他方法),而常规方法则无法。但是,对于单个应用程序程序员而言,它们的优势并不明显,但是对于创建库,然后供其他需要配置库代码行为的人或使用库的人来说,它们的实力并不明显。因此,有效使用lambda表达式的上下文是库/框架的使用/创建。

此外,由于它们描述了一次性用法代码,因此它们不必成为类的成员,而这将导致更高的代码复杂性。想象一下,每次我们要配置类对象的操作时,都必须声明一个焦点不明确的类。