第 76 讲:C# 2 之方法组转委托
新年快乐啊各位!现在是 1 月 1 日,还有两个月,这教程都更了一年了。新的一年,希望各位再接再厉!
本节内容也跟委托类型有关。可以知道,委托在 C# 里的重要性。
Part 1 从另一个维度简化委托类型实例化
前文我们介绍了匿名函数的机制,它允许我们实例化一个自己额外定义的方法,并允许捕获变量的机制。那么,假如我们的方法本身就存在呢?
考虑一点。我要遍历序列,并执行指定的操作来使用每个序列里的元素。比如:
Action<T>
是吧。很容易理解,就是把数据得到后,直接调用 Console.WriteLine
方法去输出。
可是,有必要这么写吗?你看看,我下面这样的写法对不对:
PrintList
方法的时候,参数 printer
绑定了这个方法就会自动去执行它。所以,这么写也是没错的语法。
顺带一提,这里的
Console.WriteLine
方法,你可以仔细看看这个 API。它有很多重载,正是因为如此,Console.WriteLine
这个写法才叫做方法组。但是,因为我们实例化的类型是Action<int>
类型,因此对应的签名是void Action<int>(int)
一样的东西。而Console.WriteLine
方法组里包含传入int
不返回值的重载版本,因此这样实例化是正确的。
而这样的实例化语法 new Action<int>(Console.WriteLine)
,因为参数类型是我们已知的,因此 C# 2 简化了此语法,不再要求你必须 new Action<int>
了:
是的。可以发现这样的写法简单了不少。这种语法特性叫做方法组自动转换为委托类型,简称方法组转换(Method Group Conversion),因为方法组一般也就只能用在委托里,所以“方法组转换为委托”的“为委托”不用说,都知道是转换成委托类型实例的。
当然,这种语法不一定非得用于参数,也可以是委托类型的变量定义过程:
等等。
Part 2 委托实例动词化
好吧,这个说法确实唬到人了。实际上就是一个很简单的语法特性:委托类型实例.Invoke(参数)
可以简写成 委托类型实例(参数)
。举个例子,我原来调用委托实例,可以这么写代码:
printer.Invoke(element)
是最基本的调用形式,对吧。不过,我们总是对委托类型的实例使用 .Invoke
是的。我们直接将委托类型的实例拿来执行,这样它和 .Invoke
的完整写法是没有任何执行和效率上的区别的,唯一的差别只是语法少了这么一个 .Invoke
部分。这个语法特性叫做动词化(Verbize)。为啥要叫“动词化”?因为,我们在调用执行一个方法的过程,它就好比是在完成一件事情,那么它就等于说是在做某事。这不就是动词的工作吗?而我们写上小括号就意味着,我们调用了方法,于是就相当于是在执行这个动作。那么,给委托实例后加上参数表列就等于是在执行委托实例,那么它就等于是在将一个实例(名词)直接当成动词用了。所以,我们把这种现象叫动词化。
不过,这么写就需要你额外注意和小心了。委托类型的实例是一个执行的方法列表,只是我们总是只给这个方法列表里传入一个方法组而已。实际上我们学过委托类型,都知道委托和委托之间是可以使用加减法运算的,它可以往整个委托的回调函数列表里增删执行的方法。那么,a()
的过程,如果 a
是委托类型的实例,那么 a
就好比是启动了逐方法调用的机制;但对于 a
如果是普通方法而言,就仅仅是调用当前方法了。也就是说,从写法上就不能区别它是委托类型实例还是一个普通方法的调用了。
Part 3 没了?
是的,没了。这个语言特性是从另外一个维度简化委托类型实例化的格式,因此也没有必须要单独去提及的点。