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

我已经快速阅读了微软Lambda表达式文档。

不过,这样的例子帮助我更好地理解:

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

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

242162 次浏览

很多时候,您只在一个地方使用功能,所以创建方法只会使类变得混乱。

这样可以避免在远离使用方法的地方定义只在特定位置使用一次的方法。好的用途是作为泛型算法(如排序)的比较器,然后您可以定义一个自定义排序函数,在该函数中调用排序,而不是进一步迫使您查看其他地方以查看您正在排序的对象。

这并不是真正的创新。LISP拥有lambda函数已经有30年或更长时间了。

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

想想这个例子:

 List<string> people = new List<string> { "name1", "name2", "joe", "another name", "etc" };
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;
}

它们在功能上是等价的。

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

同样,为什么需要使用foreach?你可以用一个简单的for循环来完成foreach中的所有事情,或者直接使用IEnumerable。答:你不需要它,但它使你的代码更可读。

Lambda表达式是表示匿名方法的一种简洁方式。匿名方法和Lambda表达式都允许您内联定义方法实现,但是,匿名方法显式地要求您定义方法的参数类型和返回类型。Lambda表达式使用c# 3.0的类型推断特性,该特性允许编译器根据上下文推断变量的类型。这是非常方便的,因为这节省了我们大量的输入!

这只是使用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明显地清理了语法。

Lambda表达式是一种更简单的匿名委托语法,可以在任何可以使用匿名委托的地方使用。然而,反过来就不对了;lambda表达式可以转换为表达式树,这允许很多魔术,如LINQ到SQL。

下面是一个使用匿名委托和lambda表达式的对象的LINQ表达式的示例,以显示它们是多么容易:

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

Lambda清理了c# 2.0的匿名委托语法…例如

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

在c# 2.0中是这样完成的:

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

在功能上,它们做的是完全相同的事情,只是语法更简洁。

微软为我们提供了一种更简洁、更方便的方式来创建匿名委托,即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的功能,允许用户输入简单的表达式(加法、减法等)来操作可用的数据。在前。我不得不求助于c#之外的一些脚本语言,或者不得不使用反射中的代码发射功能来动态地创建。Net代码。现在我要用表达式树。

我发现它们在一种情况下很有用,当我想为一些控件的事件声明一个处理程序时,使用另一个控件。 要做到这一点,你必须将控件的引用存储在类的字段中,这样你就可以在不同的方法中使用它们
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表达式就像代替委托实例编写的匿名方法。

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

参考文献

  1. 如何委派&接口可以互换使用?< / >

您还可以在编写作用于方法的泛型代码时使用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));

表达式允许您从方法和out参数中获取返回值

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

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

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

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

2016年,大多数流行语言都支持lambda表达式, c#是主流命令式语言进化的先驱之一。

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

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

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

此外,由于它们描述的是一次性使用的代码,所以它们不必是类的成员,这样会导致代码更加复杂。想象一下,每当我们想要配置类对象的操作时,都必须声明一个焦点不明确的类。

例如,Lambda表达式使任务简单得多

var numbers = new List<int> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };


var oddNumbers = numbers.Where(x => x % 2 != 0);
var sumOfEven = numbers.Where(x => x % 2 == 0).Sum();

在上面的代码中,因为我们使用了lambda,所以我们在一行代码中得到奇数和偶数的和。

如果没有lambda,我们将不得不使用if/else或for循环。

因此,使用lambda来简化c#中的代码是很好的。

一些关于它的文章:

https://qawithexperts.com/article/c-sharp/lambda-expression-in-c-with-examples/470

https://exceptionnotfound.net/csharp-in-simple-terms-18-expressions-lambdas-and-delegates

http://dontcodetired.com/blog/post/Whats-New-in-C-10-Easier-Lambda-Expressions