首页 文章

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

提问于
浏览
289

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

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

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

不过,我不明白为什么会有这样的创新 . 它只是一种方法,当“方法变量”结束时死亡,对吗?为什么我应该使用它而不是真正的方法?

14 回答

  • 34

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

  • 21

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

  • 132

    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 > 5abstract syntax tree的表示 . LINQ to SQL依赖于这种行为,能够将C#表达式转换为服务器端过滤/排序等所需的SQL表达式 .

  • 6

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

    考虑这个例子:

    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;
     }
    

    这些功能相同 .

  • 0

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

    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;};
    }
    

    更容易 .

  • 5

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

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

    在C#2.0中完成了这样:

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

    在功能上,它们完全相同,它只是一个更简洁的语法 .

  • 11

    这只是使用lambda表达式的一种方法 . 您可以使用lambda表达式 anywhere 您可以使用委托 . 这允许你做这样的事情:

    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);
    

    EDIT

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

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

    Lambda显着清理了这种语法 .

  • 28

    Microsoft为我们提供了一种更简洁,更方便的方法来创建名为Lambda表达式的匿名委托 . 但是,本声明的 expressions 部分没有引起太多关注 . 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();
            }
        }
    }
    

    这个例子很简单 . 我相信你在想,"This is useless as I could have directly created the delegate instead of creating an expression and compiling it at runtime" . 你会是对的 . 但这为表达树提供了基础 . Expressions名称空间中有许多表达式,您可以构建自己的表达式 . 我想你可以看到,如果你不确切知道算法在设计或编译时应该是什么,这可能会有用 . 我在某个地方看到了一个用来编写科学计算器的例子 . 您也可以将它用于Bayesian系统或genetic programming(AI) . 在我的职业生涯中,有几次我不得不编写类似Excel的功能,允许用户输入简单的表达式(加法,减法等)来操作可用数据 . 在pre-.Net 3.5中,我不得不求助于C#外部的一些脚本语言,或者必须在反射中使用代码发射功能来动态创建.Net代码 . 现在我会使用表达式树 .

  • 3

    它节省了必须具有仅在特定位置使用一次的方法,而不是远离它们所使用的位置 . 良好的用途是作为通用算法(如排序)的比较器,然后您可以在其中定义自定义排序函数,您可以在其中调用排序而不是进一步强制您查看其他位置以查看您正在排序的内容 .

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

  • 4

    lambda表达式就像一个匿名的代替委托实例编写的方法 .

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

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

    输入参数值为x(在=>的左侧)函数逻辑是x * x(在=>的右侧)

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

    x => {return x * x;};
    

    Example

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

    Console.WriteLine(MyMethod(x => "Hi " + x));
    
        public static string MyMethod(Func<string, string> strategy)
        {
            return strategy("Lijo").ToString();
        }
    

    References

  • 268

    您还可以在编写通用代码时使用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));
    
  • 0

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

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

  • 4

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

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

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

    2016年,大多数流行语言都得到了支持,而C#是主流命令式语言在这种演变中的先驱之一 .

  • 83

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

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

相关问题