我已经快速阅读了Microsoft Lambda Expression文档。
但是,这种示例有助于我更好地理解:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
但是,我仍然不明白为什么它是如此创新。这只是“方法变量”结束时消失的方法,对吗?为什么要使用此方法而不是实际方法?
我已经快速阅读了Microsoft Lambda Expression文档。
但是,这种示例有助于我更好地理解:
delegate int del(int i);
del myDelegate = x => x * x;
int j = myDelegate(5); //j = 25
但是,我仍然不明白为什么它是如此创新。这只是“方法变量”结束时消失的方法,对吗?为什么要使用此方法而不是实际方法?
Answers:
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<T>
参数,编译器将通过lambda而不是匿名委托生成表达式树:
void Example(Predicate<int> aDelegate);
像这样
Example(x => x > 5);
变成:
void Example(Expression<Predicate<int>> expressionTree);
后者将传递描述该表达式的抽象语法树的表示形式x > 5
。LINQ to SQL依靠此行为,能够将C#表达式转换为服务器端进行过滤/排序等所需的SQL表达式。
匿名函数和表达式对于一次性方法很有用,这些方法无法从创建完整方法所需的额外工作中受益。
考虑以下示例:
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;
}
这些在功能上是等效的。
当我想使用另一个控件声明某个控件事件的处理程序时,我发现它们很有用。为此,通常必须将控件的引用存储在类的字段中,以便可以将其用于与创建方法不同的方法中。
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表达式。这使您可以执行以下操作:
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大大清除了该语法。
string
并返回bool
)作为该Find
方法本身的参数。
微软为我们提供了一种更清洁,更便捷的方式来创建名为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();
}
}
}
这个例子很简单。而且我确信您在想:“这没用,因为我可以直接创建委托,而不是在运行时创建表达式并进行编译”。你会是对的。但这为表达式树提供了基础。表达式名称空间中有许多表达式,您可以构建自己的表达式。我认为您可以看到,当您不确切知道算法在设计或编译时应该使用什么时,这可能会很有用。我在某处看到了一个使用此示例编写科学计算器的示例。您也可以将其用于贝叶斯系统或遗传编程(AI)。在我的职业生涯中,有几次我不得不编写类似于Excel的功能,该功能允许用户输入简单的表达式(加法,减法等)以对可用数据进行操作。在.Net 3.5之前的版本中,我不得不求助于C#外部的某些脚本语言,或者不得不使用反射代码的功能来动态创建.Net代码。现在,我将使用表达式树。
您还可以在编写通用代码以对您的方法进行操作时找到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));
表达式使您可以从方法中获取返回值以及参数
var timeTaken = Measure(() => returnValue = yourMethod(param, out outParam));
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(Func<string, string> strategy)
{
return strategy("Lijo").ToString();
}
参考文献
很多时候,您只在一个地方使用功能,因此制作方法只会使类混乱。
这也许是关于为什么使用lambda表达式的最佳解释-> https://youtu.be/j9nj5dTo54Q
总之,这是为了提高代码的可读性,通过重用而不是复制代码来减少出错的机会,并利用幕后发生的优化。
Lambda表达式和匿名函数的最大好处是,它们允许库/框架的客户端(程序员)通过给定库/框架中的代码注入功能(因为它是LINQ,ASP.NET Core和许多其他方法),而常规方法则无法做到。但是,对于单个应用程序程序员来说,它们的优势并不明显,但是对于创建库的人(那些稍后将要配置库代码的行为的其他人)或使用库的人来说,它们的优势并不明显。因此,有效使用lambda表达式的上下文是库/框架的使用/创建。
同样,由于它们描述了一次性用法代码,因此它们不必成为类的成员,而这将导致更高的代码复杂性。想象一下,每次我们想要配置类对象的操作时,都必须声明一个焦点不明确的类。
delegate
是在C#中,我强烈建议阅读此之前阅读本页面的其余部分:stackoverflow.com/questions/2082615/...