之前在用LINQ TO SQL 时使用过 “=>”运算符来进行数据的操作,当时不是很明白这个运算符的来源。今天碰到一段代码也使用这个运算符,甚是好奇。
这个运算符是C#3.0之后才加进来的,是Lambda运算符,该运算符读作”goes to”。该运算符左边是输入的参数,右边可以是一个语句也可以是一个程序块。Lambda表达式是用来写一个匿名的函数,也可以当作一个匿名函数传入到另一个函数中被其使用。
在介绍Lambda表达式之前,先了解一下在Lambda出现之前,C#中是如何将函数作为参数传递给方法的。我举一个排序的例子来说明这个方法。
Named Method
在Lambda之前可以使用委托来完成传递函数的工作,这个很类似于C++中的函数指针,但是较之函数指针要安全。以以下排序为例
class Program
{
static void Main(string[] args)
{
int[] numbers = { 5, 4, 1, 3, 9, 8, 6, 7, 2, 0 };
Sort(ref numbers, asc);
Sort(ref numbers, desc);
}
//委托
public static delegate bool Compare(int i, int j);
//正序比较函数
private static bool asc(int i, int j)
{
return i >= j;
}
//逆序比较函数
private static bool desc(int i, int j)
{
return i <= j;
}
//排序函数
public static void Sort(ref int[] arr, Compare cmp)
{
for (int i = 0; i < arr.Length; i++)
{
for (int j = 0; j < arr.Length - 1 - i; j++)
{
if (cmp(arr[j], arr[j + 1]))
{
Swap(arr[j], arr[j + 1]);
}
}
}
}
}
上面这段程序中我们将比较函数作为参数传入排序算法中,这样我们就只要写一段排序算法就可以同时很方便的实现正序和逆序的运算。这个例子中可能不是很明显,加入我做的操作不是排序而是筛选,那么将筛选算法当作参数传入就可以很好的提高程序的效率,因为当出现新的过滤规则的时候你只需要写一个新的过滤算法,而不需要实现整个过滤方法。(可以http://goo.gl/7tG8B为例)
Anonymous Methods
如果使用匿名方法,上面的排序方法调用就可以修改为。其实就是很坑爹的把委托和那个算法都写在了一起。
Sort(ref numbers, delegate(int i, int j) { return i >= j; });
Lambda Expression
用Lambda表达式重写上面的Sort调用,代码就变成了:
Sort(ref numbers, (i, j) => i >= j );
我们可以发现代码变得相对简单了很多。
Lambda Stateent
Lambda 语句和Lambda表达式的区别就是Lambda语句有一对”{ }”,在这个花括号内,你可以干任何你想干的事情,如果用Lambda 语句写上面的Sort的话,可以写成写成下面这样。
Sort(ref numbers, (i, j) =>{
if (i > j)
return true;
if (i == j)
return true;
if (i < j)
return false;
});
我知道这么写很傻,我只是想说明一下这个语句块内可以写很多很多的表达式,但是如果表达式多了的话就不像是一个匿名块该干的事情了!
Summary
从我这个例子中只是很肤浅的介绍了一下Lambda这个东西是什么,你可能会觉得这个东西其实没什么用。我认为如果你准备用Lambda表达式写的那段程序块是一个比较频繁使用的东西,写成一个有名字的会比较好,这样不仅可以增加程序的可读性也可以让代码变得比较好维护。这个Lambda最好的用武之地莫过于在Linq中,因为很多Linq语句中的查询都是很简单的一两个表达式,而且关键的是他们并没有特殊的含义也不需要被重用,所以这个Lambda就可以很好的使用Linq中的需求。也许微软就是为了Linq才在C#中实现Lambda的吧。
Reference
Lambda 表达式(C# 编程指南):http://msdn.microsoft.com/zh-cn/library/bb397687.aspx
C# 3.0特性之Lambda表达式:http://www.cnblogs.com/SpadeQ/articles/1246226.html