先来看两段C#代码,来比较Lambda表达式:
- Thread t = new Thread(() =>
- {
- AddIt AddDelegate = new AddIt(AddItem);
- this.Invoke(AddDelegate);
- });
- Thread t3 = new Thread(new ThreadStart(() =>
- {
- AddIt AddDelegate = new AddIt(AddItem);
- this.Invoke(AddDelegate);
- }));
这两种写法都是可以的,出来的IL也一样,但是意义是不同的,后者相当于匿名方法,前者
更像是"匿名"的委托,其实这样写:
- Thread t2 = new Thread(() =>
- {
- this.Invoke(new AddIt(() => { this.listBox1.Items.Add("bbb"); }));
- });
这个跟上面两种写法也是一样的效果,初次接触的时候,可能大家跟我一样会有些迷茫,Lamdba表达式到底该怎么用呢?
首先还是要弄清Lamdba表达式的几个特性:
1. Lamdba 表达式是一个委托类型:
- MethodInvoker invoker = () => { Console.WriteLine(); };
- //is actually equal to the following form.
- MethodInvoker invoker = delegate() { Console.WriteLine(); };
- //这里是Lamdba 表达式的匿名委托的用法
2. Lamdba 表达式可以用作匿名方法
- MethodInvoker invoker = new MethodInvoker(() => { Console.WriteLine(); });
- //相当于:
- MethodInvoker invoker = new MethodInvoker(MyFunc);
- partial void MyFunc()
- {
- Console.WriteLine();
- }
我们知道, 当构造一个新的委托的时候, 他的构造器需要一个函数指针作参数,这个函数指针是委托类型的
实际上,当我们这样去new 一个委托的时候:
MethodInvoker invoker = new MethodInvoker(MyFunc);
"MyFunc" 就是一个委托,而不只是一个函数名的存在. 编译器将为这个构造函数生成一个匿名委托:
MethodInvoker invoker = new MethodInvoker(delegate() { MyFunc(); });
可以这样理解编译器的行为: 匿名方法其实也就是委托。
那么为什么我们可以这么写呢:
MethodInvoker invoker = () => { Console.WriteLine(); };
我们来看一看:
首先,这个委托的构造器需要一个委托参数,所以通常我们得这样写:
MethodInvoker invoker = new MethodInvoker(delegate() { MyFunc(); });
但是匿名的delegate 可以转化成函数指针 (void() target):
所以这样写是可以的:
- MethodInvoker invoker = new MethodInvoker(MyFunc);
- //而匿名的委托又可以描述为Lambda表达式
- MethodInvoker invoker = new MethodInvoker(() => { Console.WriteLine(); });
- //另外一方面,由于编译器对"宽松委托"的支持, MethodInvoker类委托可以转化成匿名类委托:
- MethodInvoker invoker = delegate() { Console.WriteLine(); };
- //而匿名的委托又可以用Lambda表达式来描述
- MethodInvoker invoker = () => { Console.WriteLine(); };
从上面,我们可以看到一个复杂的委托是如何转化成简洁的Lambda表达式的。这对程序员来说无疑又是提高生产力的一个体现!
-------------------------------------------------------------------------------------------------------------------
C#的Lambda 表达式都使用 Lambda 运算符 =>,该运算符读为“goes to”。语法如下: 形参列表=>函数体 函数体多于一条语句的可用大括号括起。类型
可以将此表达式分配给委托类型,如下所示:123 | delegateintdel(inti); delmyDelegate=x=>{returnx*x;}; intj=myDelegate(5); //j=25 |
123 | usingSystem.Linq.Expressions; //... Expression<del>=x=>x*x; |
特殊
下列规则适用于 Lambda 表达式中的变量范围: 捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。 在外部方法中看不到 Lambda 表达式内引入的变量。 Lambda 表达式无法从封闭方法中直接捕获 ref 或 out 参数。 Lambda 表达式中的返回语句不会导致封闭方法返回。 Lambda 表达式不能包含其目标位于所包含匿名函数主体外部或内部的 goto 语句、break 语句或 continue 语句。 Lambda表达式的本质是“匿名方法”,即当编译我们的程序代码时,“编译器”会自动将“Lambda表达式”转换为“匿名方法”,如下例:123 | string []names={ "agen" , "balen" , "coure" , "apple" }; string []findNameA=Array.FindAll< string >(names, delegate (stringv){returnv.StartsWith( "a" );}); string []findNameB=Array.FindAll< string >(names,v=>v.StartsWith( "a" )); |
12 | string []findNameA=Array.FindAll< string >(names, delegate (stringv){returnv.StartsWith( "a" );}); string []findNameB=Array.FindAll< string >(names, delegate (stringv){returnv.StartsWith( "a" );}); |
123456789101112131415 | classTest { delegateintAddHandler(intx,inty); staticvoidPrint(AddHandleradd) { Console.Write(add(1,3)); } staticvoidMain() { Print((x,y)=>x+y); Print((x,y)=>{intv=x*10;returny+v;}); Console.Read(); } } |
1234567891011121314151617181920 | classTest { delegateTAddHandler<T>(Tx,Ty); staticvoidPrint(AddHandler< int >test) { Console.WriteLine( "inttype:{0}" ,test(1,2)); } staticvoidPrint(AddHandler< double >test) { Console.WriteLine( "doubletype:{0}" ,test(1d,2d)); } staticvoidMain() { Print((x,y)=>x+y); Console.Read(); } } |
1 | Print((intx,inty)=>x+y); |