2008-10-03 60 views

回答

256

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表达式。

4

很多时候,你只是在一个地方使用功能,所以使一个方法只是使课堂更加混乱。

11

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

而这不是一项真正的创新。 LISP具有约30年或更长时间的lambda功能。

124

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

考虑这个例子:

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

这些是功能上等同的。

+6

如何定义Find()方法来处理这个lambda表达式? – 2008-10-03 15:16:51

+1

谓词是Find方法所期待的。 – 2008-10-03 15:19:28

+1

由于我的lambda表达式与Predicate 的契约匹配,Find()方法接受它。 – 2008-10-03 15:21:01

3

这是一种采取小型操作并将其放置在非常接近其使用位置的方式(与声明接近其使用点的变量不同)。这应该让你的代码更具可读性。通过对表达式进行匿名处理,如果某个人在其他地方使用了该功能并将其修改为“增强”该功能,那么对于某人破坏客户端代码而言,也会使其变得更加困难。

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

4

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

27

这只是使用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"); 

此代码将在列表中找到单词“你好”相匹配的条目。另一种方式做,这是真正的委托传递给查找方法,像这样:

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明显清除了该语法。

33

拉姆达的清理C#2.0的匿名委托语法......例如

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

做C#2.0中是这样的:

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

功能上,他们做同样的事情,它只是一个更简洁的语法。

21

微软为我们提供了一种更简洁,更便捷的创建名为Lambda表达式的匿名委托的方法。然而,本声明的部分内容表达式没有多少关注。微软发布了一个完整的命名空间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代码。现在我会使用表达式树。

79

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

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

容易得多。

4

lambda表达式就像代替委托实例写入的匿名方法。

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

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

The input parameter value is x (on the left side of =>)

The function logic is x * x (on the right side of =>)

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?
5

您也可以在编写通用代码来作用于你的方法使用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)); 

表达允许你从你的方法,并从获得的返回值PARAM以及

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

创新是在类型安全和透明。尽管您没有声明lambda表达式的类型,但它们被推断出来,并且可以被代码搜索,静态分析,重构工具和运行时反射使用。

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

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

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

0

这也许是为什么使用lambda表达式最好的解释 - >https://youtu.be/j9nj5dTo54Q

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

相关问题