C#2.0之前, 如果一个方法或者变量需要使用委托(delegate)时, 则之前必须创建一个命名方法, 并在需要委托的位置传入这个名称. 比如有一个针对int类型的数据处理, 目的是筛选出一个int数组中为奇数的元素, 或者其它一些满足条件的元素...
public class Commom { //命名一个委托方法 public delegate bool IntFilter(int i); //筛选出符合委托方法所要求的int, 返回一个int[] public static int[] FilterArrayOfInts(int[] ints, IntFilter filter) { ArrayList aList = new ArrayList(); foreach (int i in ints) if (filter(i)) aList.Add(i); return (int[])aList.ToArray(typeof(int)); } }
Commom类建立了一个统一的模型, 这个模型主要用于传入一个delegate方法, 可以获得这个delegate方法条件所要求的数字. 具体这个delegate方法可以写在另一个类中, 可以写很多方法, 检测是否是奇数, 是否是偶数, 这个数是否是3的倍数...这个根据需要自己写. 这样写可以提高Commom类的可重用程度.
//根据需要, 自己定义筛选方法 public class MyIntFilter { //自己定义的筛选方法1: 检测是否是奇数 public static bool IsOdd(int i) { return ((i & 1) == 1); } //自己定义的筛选方法2: 检测是否是偶数 public static bool IsEven(int i) { return ((i & 1) != 1); } //...根据需要还可以定义其它筛选方法 }
调用MyIntFilter中的筛选方法:
int[] nums = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //筛选出奇数 int[] oddNums = Commom.FilterArrayOfInts(nums, MyIntFilter.IsOdd); //筛选出偶数 int[] evenNums = Commom.FilterArrayOfInts(nums, MyIntFilter.IsEven); //测试结果, 打印出oddNums和evenNums Console.WriteLine("Print oddNums:"); foreach (int i in oddNums) Console.Write(i + " "); Console.WriteLine("Print evenNums:"); foreach (int i in evenNums) Console.Write(i + " ");
为什么要使用匿名方法? 答: 偷懒. 为每一个筛选策略专门写一个方法很多时候会令人很烦, 很多方法可能只被用到一次两次, 且为每个方法都起一个好听的名字并在调用这些方法的时候传入这些方法名令人不爽, 因此C#2.0的时候可以使用"匿名方法"解决这一问题:
int[] nums = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //筛选出奇数 int[] oddNums = Commom.FilterArrayOfInts(nums, delegate(int i) { return ((i & 1) == 1); }); Console.WriteLine("Print oddNums:"); foreach (int i in oddNums) Console.Write(i + " ");
这时筛选出了int数组中所有的奇数, 而没有使用MyIntFilter类里面用于判断是否是奇数的方法. 这种匿名的方法好处在于省去了维护程序代码中上下文的精力.
lambda表达式的形式如下:
(param1, param2, param3...)=>{doSomethingWithParam1, doSomethingWithParam2, doSomethingWithParam3...}
lambda的好处在于哪里? 最关键的作用可能是可读性提高了, 简洁明了, 只需要列出方法体中需要使用到的参数, 然后加上=>{}, 在大括号中写方法体. 但注意的是传入的参数类型要满足之前delegate定义的输入类型, 并返回delegate定义的返回类型.
同样是上面的要求, 从int数组中筛选出奇数, 使用lambda表达式就是这样写:
int[] nums = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //筛选出奇数 int[] oddNums = Commom.FilterArrayOfInts(nums, (i) => ((i & 1) == 1)); foreach (int i in oddNums) Console.Write(i + " ");
比较三种做法, 可以发现lambda表达式最简洁. 但并不是所有的这种情况都使用lambda表达式. 对于比较复杂的算法, 需要重用的算法, 最好还是使用第一种"命名方法", 因为这样做, 在任何时候任何开发者都可以很方便的直接调用方法, 而不需考虑这些细节.
C#3.0很多新特性几乎都暗示着是为Linq而服务的, Lambda表达式也不例外, 因为一个Linq查询通常只需要调用一次, 不需要为每一个查询专门命名一个方法.