欢迎光临散文网 会员登陆 & 注册

第 76 讲:C# 2 之方法组转委托

2022-01-01 10:38 作者:SunnieShine  | 我要投稿

新年快乐啊各位!现在是 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(参数) 可以简写成 委托类型实例(参数)。举个例子,我原来调用委托实例,可以这么写代码:

第 5 行代码的 printer.Invoke(element) 是最基本的调用形式,对吧。不过,我们总是对委托类型的实例使用 .Invoke 是不是又有点过于繁琐了?反正委托的实例都是这么写的,那么干脆我们就把委托类型的实例当成一个执行的方法来执行算了:

是的。我们直接将委托类型的实例拿来执行,这样它和 .Invoke 的完整写法是没有任何执行和效率上的区别的,唯一的差别只是语法少了这么一个 .Invoke 部分。这个语法特性叫做动词化(Verbize)。为啥要叫“动词化”?因为,我们在调用执行一个方法的过程,它就好比是在完成一件事情,那么它就等于说是在做某事。这不就是动词的工作吗?而我们写上小括号就意味着,我们调用了方法,于是就相当于是在执行这个动作。那么,给委托实例后加上参数表列就等于是在执行委托实例,那么它就等于是在将一个实例(名词)直接当成动词用了。所以,我们把这种现象叫动词化。

不过,这么写就需要你额外注意和小心了。委托类型的实例是一个执行的方法列表,只是我们总是只给这个方法列表里传入一个方法组而已。实际上我们学过委托类型,都知道委托和委托之间是可以使用加减法运算的,它可以往整个委托的回调函数列表里增删执行的方法。那么,a() 的过程,如果 a 是委托类型的实例,那么 a 就好比是启动了逐方法调用的机制;但对于 a 如果是普通方法而言,就仅仅是调用当前方法了。也就是说,从写法上就不能区别它是委托类型实例还是一个普通方法的调用了。

Part 3 没了?

是的,没了。这个语言特性是从另外一个维度简化委托类型实例化的格式,因此也没有必须要单独去提及的点。


第 76 讲:C# 2 之方法组转委托的评论 (共 条)

分享到微博请遵守国家法律