我已经快速阅读了Microsoft Lambda Expression文档.
这种例子帮助我更好地理解了:
delegate int del(int i); del myDelegate = x => x * x; int j = myDelegate(5); //j = 25
不过,我不明白为什么会有这样的创新.它只是一种在"方法变量"结束时死亡的方法,对吗?为什么我应该使用它而不是真正的方法?
Lambda表达式是匿名委托的一种更简单的语法,可以在任何可以使用匿名委托的地方使用.然而,事实恰恰相反; 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表达式和匿名委托比编写单独的函数更有优势:它们实现了闭包,允许您将本地状态传递给函数,而无需向函数添加参数或创建一次性使用对象.
表达式树是C#3.0的一个非常强大的新功能,它允许API查看表达式的结构,而不仅仅是获取对可以执行的方法的引用.API只需要将一个委托参数放入Expression
参数中,编译器将从lambda而不是匿名委托生成表达式树:
void Example(PredicateaDelegate);
叫做:
Example(x => x > 5);
变为:
void Example(Expression> expressionTree);
后者将传递描述表达式的抽象语法树的表示x > 5
.LINQ to SQL依赖于这种行为,能够将C#表达式转换为服务器端过滤/排序等所需的SQL表达式.
匿名函数和表达式对于无法从创建完整方法所需的额外工作中受益的一次性方法非常有用.
考虑这个例子:
string person = people.Find(person => person.Contains("Joe"));
与
public string FindPerson(string nameContains, Listpersons) { foreach (string person in persons) if (person.Contains(nameContains)) return person; return null; }
这些在功能上是等同的.
我发现它们在我想要使用另一个控件声明某个控件的事件的处理程序的情况下很有用.通常,您必须在类的字段中存储控件的引用,以便您可以使用与创建它们不同的方法来使用它们.
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;}; }
更容易.
Lambda清理了C#2.0的匿名委托语法......例如
Strings.Find(s => s == "hello");
是在C#2.0中完成的,如下所示:
Strings.Find(delegate(String s) { return s == "hello"; });
在功能上,它们完全相同,它只是一个更简洁的语法.
这只是使用lambda表达式的一种方法.您可以在任何可以使用委托的地方使用lambda表达式.这允许你做这样的事情:
Liststrings = new List (); 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方法,如下所示:
Liststrings = new List (); 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显着清理了该语法.
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> 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名称空间中有许多表达式,您可以构建自己的表达式.我想您可以看到,如果您不确切知道算法在设计或编译时应该是什么,这可能会有用.我在某个地方看到了一个用来编写科学计算器的例子.您也可以将它用于贝叶斯系统或遗传编程(AI).在我的职业生涯中,有几次我必须编写类似Excel的功能,允许用户输入简单的表达式(加法,减法等)来操作可用数据.在pre-.Net 3.5中,我不得不求助于C#外部的一些脚本语言,或者必须在反射中使用代码发射功能来动态创建.Net代码.现在我会使用表达式树.
它节省了必须具有仅在特定位置使用一次的方法,而不是远离它们被使用的位置.良好的用途是作为通用算法(如排序)的比较器,然后您可以在其中定义自定义排序函数,您可以在其中调用排序而不是进一步强制您查看其他位置以查看您正在排序的内容.
这并不是一项创新.LISP具有λ功能约30年或更长时间.
您还可以在编写通用代码时使用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));
Lambda表达式是表示匿名方法的一种简洁方法。匿名方法和Lambda表达式都允许您内联定义方法实现,但是,匿名方法明确要求您定义方法的参数类型和返回类型。Lambda表达式使用C#3.0的类型推断功能,该功能允许编译器根据上下文推断变量的类型。这非常方便,因为这可以节省很多打字时间!
lambda表达式类似于代替委托实例编写的匿名方法.
delegate int MyDelagate (int i); MyDelagate delSquareFunction = x => x * x;
考虑lambda表达式 x => x * x;
输入参数值为x(在=>的左侧)
函数逻辑是x*x(在=>的右侧)
lambda表达式的代码可以是语句块而不是表达式.
x => {return x * x;};
例
注意:Func
是预定义的通用委托.
Console.WriteLine(MyMethod(x => "Hi " + x)); public static string MyMethod(Funcstrategy) { return strategy("Lijo").ToString(); }
参考
委托和界面如何可以互换使用?