关于 委托 的一些补充
忙活了几天,终于把关于委托的内容写完了,我是指把我知道的关于委托的内容写完了。文章发布的一瞬间,心里有点慌,总感觉忘了什么。反正今天是周五了,工作先放放~~闭上眼睛休息的同时,也在琢磨着是否有些疏漏,好像想起点儿什么,却又抓不住,这时旁边看我文章的虾米突然问我,这委托用起来怎么这么麻烦啊?麻烦,有吗??心里一突,想起来漏掉什么了。。。
委托和什么打交道最多?当然是方法。定义委托的实例需要指定方法,异步调用还需要指定回调的方法(回调函数),如果这些方法十分复杂还则罢了,可是有些时候,尤其是回调函数的内容及其简单,一句话甚至不需要回调函数,程序的逻辑也可以。为了满足委托的要求,却要反复的定义这些方法,有点烦啊…
从.Net2.0开始,这个问题开始有了解决的办法,那就是匿名方法,看下面的例子
1: private void button1_Click(object sender, EventArgs e)
2: {
3: SampleDelegate dele = new SampleDelegate(m1);
4: dele.BeginInvoke(new AsyncCallback(finish), null);
5: }
6:
7: private void finish(IAsyncResult result)
8: {
9: MessageBox.Show(result.AsyncState.ToString());
10: }
为了进行异步调用,我定义了finish方法,虽然我什么都不需要做。匿名方法的出现,使得我有了另外一个选择。所谓匿名方法,当然就是定义一个没有名字的方法。实际上就是把原来的方法体直接写在调用的地方(当然没那么直接~),看下面的代码
1: private void button1_Click(object sender, EventArgs e)
2: {
3: SampleDelegate dele = new SampleDelegate(m1);
4: dele.BeginInvoke(new AsyncCallback(
5: delegate(IAsyncResult result) { MessageBox.Show(result.AsyncState.ToString());}
6: ), null);
7: }
我们用第5行的
5: delegate(IAsyncResult result) { }
替换了原来定义的finish方法。这里的delegate告诉编译器我后面的代码是个方法,你编译的时候请自动创建它。()中是这个方法的参数,{}中的内容是这个方法的方法体。一切就这么简单,我相信你只要自己把代码敲一遍就会使用了。
这就是匿名方法,实际上它只是让我们在写代码的时候简化了方法的定义过程。有人说匿名方法真是垃圾,它什么用都没有,它只是让我少敲了一个方法的名字而已,并且它还让我调用它的代码看上去更臃肿了。事实上似乎真的如此,但匿名方法真的这么一无是处吗?
首先,我并不赞成你将一个复杂的方法替换成匿名方法,我认为匿名方法只适用于必须的空方法或一句话方法;
其次,使用匿名方法你不用冥思苦想一个合适的方法名给你的方法。你不觉得写程序的时候,命名是个痛苦的事情吗?
最后,使用匿名方法免除了你在查看一个数千行的代码的时候,为了明白方法的作用,不停的跳来跳去的麻烦。(很多时候被调用的方法很难紧挨着调用它的方法)
到了.Net3.0(也许是3.5,记不清了),我们又有了新的选择,那就是Lambda表达式。什么是Lambda表达式?Lambda表达式代表了一个匿名方法,没错,它将一个匿名方法以表达式的方式进行书写。Lambda表达式的结构就像 ()=>{ }; 它被=>符合分成两个部分(=>读音是Goes to),左边()里面是参数列表,右边{}里面是要执行的语句,把前面的程序改成Lambda表达式:
1: private void button1_Click(object sender, EventArgs e)
2: {
3: SampleDelegate dele = new SampleDelegate(m1);
4: dele.BeginInvoke(new AsyncCallback(
5: (IAsyncResult result) => { MessageBox.Show(result.AsyncState.ToString());}
6: ), null);
7: }
你还可以做得更简单
1: private void button1_Click(object sender, EventArgs e)
2: {
3: SampleDelegate dele = new SampleDelegate(m1);
4: dele.BeginInvoke(new AsyncCallback(
5: (result) => {MessageBox.Show(result.AsyncState.ToString()); }
6: ), null);
7: }
没错,你可以忽略参数类型。编译器会自动识别参数类型的。它是如何做到的?当然是根据调用者啊,编译器查看调用者调用的委托类型的签名就可以推断出
Lambda表达式的参数类型了。还能更简单吗?当然
1: private void button1_Click(object sender, EventArgs e)
2: {
3: SampleDelegate dele = new SampleDelegate(m1);
4: dele.BeginInvoke(new AsyncCallback(
5: r => { MessageBox.Show(r.AsyncState.ToString());}
6: ), null);
7: }
去掉括号,更改参数名称,这样的一个Lambda表达式看上去是不是比匿名方法优雅多了?或许,这就是编码的艺术了。
从匿名方法到Lambda表达式,我们的程序本身的性能没有任何的改变,但我们的编码确变得越来越简单。如果你觉得这些都没有用,OK,你完全可以使用传统的方法去写你的代码,但对于追求艺术的人们,正是这些改变,为我们带来了幸福。