简介:本文简单介绍委托、匿名方法、扩展方法和 Lambda Expression。 仅供初次接触这些技术的同学参考学习。
List<int> list = new List<int> { 2, 3, 76, 63, 4, 64, 23 };
//当你第一次看到下面这条语句时,你可能很难马上理解它的含义
list.Where( x => x >20 );
下面我们来一步一步演示它的演化过程。
1. delegate
委托是一种类型,它相当于 C++ 中的函数指针,指向一个特定的函数。
如:public delegate int MyDelegate(int i);
它定义了一个返回值为 int 且含有一个 int 型参数的委托 MyDelegate,凡是符合这种形式的方法都可以赋给我们的委托。
下面我们定义一个方法:
public static int Fun(int i) { return i * 5; }
这个方法符合我们定义的委托的形式:返回值为 int ,一个 int 型参数。 所以可以用来实例化我们的委托。
MyDelegate del = new MyDelegate(Fun);
//or
//MyDelegate del = Fun;
现在就可以用委托来调用我们的方法了:
del(6);
委托其实是一个类,所以只能在类的外部定义。 那我们为什么多此一举用委托来调用函数呢?
主要是一个委托可以指向具相同形式的多个函数,这使得委托可以实现很多灵活的应用。
如实现很多好的设计模式,像观察者模式等, C# 中的 event 等都是基于委托实现的。
2. Annonymous Method(匿名方法)
匿名方法就是一个没有名字的方法,下面我们赋给我们的委托一个匿名的方法
MyDelegate del = delegate(int i) { return i * 6; };
3. Lambda Expression
有了 Lambda Expression 我们就可以这样写了
MyDelegate del = i => i * 6;
是不是更简单了 => 左边的 i 是参数,右边是函数体(返回 i*6)。
当有多个参数或函数体有多条语句时就可以写成这样了
MyDelegate del = (x, y) => { x = 3; y = 5; return x + y; };
4. Extension Methods
扩展方法可以给一个不可变的类添加方法,扩展方法是一个静态方法,不过可以用类的实例进行调用,
看起来和调用类中的普通方法没什么区别。
下面我们扩展 string 类,增加一个 ToInt32Extension 方法
public static class ExtensionMethods
{
public static int ToInt32Extension(this string s)
{
return Int32.Parse(s);
}
}
扩展方法必须放在一个静态非泛型的类中,否则编译会出错。
this 是扩展方法的关键字,后面跟上你要扩展的类。
当然扩展方法也可以带参数,如
public static class ExtensionMethods
{
public static int ToInt32ExtensionAddInteger(this string s,int value)
{
return Int32.Parse(s) + value;
}
}
下面我们就可以用类的实例就行调用了
string str = "45";
s.ToInt32Extension();
也可直接调用静态方法如:
ToInt32Extension(s);
不过不会这样用,这就体现不出扩展的意思了,但运行时应该就是把我们实例的引用传到静态方法中。
扩展方法在 LINQ 查询中用的最多,看我们扩展自己的 where 查询子句。
public static IEnumerable<TSource> MyOwnWhere<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
foreach (var item in source)
{
if (predicate(item))
yield return item;
}
}
IEnumerable<TSource>是我们要扩展的类,它是一个泛型类。
同样它返回一个 IEnumerable<TSource> 集合。
Func<TSource, bool>是参数,Func是一个泛型委托,它的返回值是 bool 类型。
yield 的意思是将所有满足条件的 item 构成一个集合返回。
这样我们就可以把筛选的条件作为函数传进去,当然就可以传匿名方法和 Lambda Expression 了。
最后让我们测试一下
List<int> list = new List<int> { 2, 3, 76, 63, 4, 64, 23 };
//我们可以传一个匿名的方法进去
//var list2 = list.MyOwnWhere(delegate(int x){return x > 20;});
这里你可能要问我们没有扩展 List<T> 类啊? 为什么 List 的实例也能访问到呢?
这是由于我们已经扩展了 IEnumerable<T> 接口 ,当你扩展一个接口时,
所有实现这个接口的类的实例也都能访问到扩展方法了。当然 List<T> 是集合类,它实现了 IEnumerable<T> 接口。
但更一般的是传一个 Lambda Expressions 进去
你在LINQ查询中经常看到
var list2 = list.MyOwnWhere( x => x > 20);
foreach (int x in list2)
{
Console.WriteLine(x);
}
最后它将返回数组中大于 20 的数字。
其它的 LINQ 扩展查询方法如 Select、Single、order by 等都是这样实现的。
现在希望你再看到这种表达式时不要感觉陌生了。