background image

运算符重载

除了

J#外,所有微软支持的.NET 开发语言现在均支持运算符重载,因此纯粹为 C#简

化写法一样特性现已成为一种

.NET 开发中值得研究的一项重要语言特性。有人认为运算符

重载其实就是简化写法,满足模拟基本类型操作的小功能,没有必要深究。但我觉得要多思
考一层,为什么我们总希望模拟基本类型的操作?因为运算符重载能够将操作中缀化,能
够自动推测静态过程的主体。

首先是操作中缀化。函数调用其实是一种前缀操作,函数(代表操作)总是在参数(代

表操作数)之前写出。这样执行序列操作时运行的顺序其实和书写的顺序相反:

H(x,y)
G(H(x, y), z)
F(G(H(x, y), z), w)
序列运行的顺序是

H->G->F 但是却要反过来写,二元参数距离函数名越来越远。我们

按照计算机执行的顺序思考,却要反过来写,多少有些不爽。成员函数与扩展方法的写法则
是将操作数(对象)写在前面:

x.H(y)
x.H(y).G(z)
x.H(y).G(z).F(w)
这样就将书写的顺序正过来了。这是一个甚好的方案,但是在不具备扩展方法的今天,

有些事情是成员函数做不了的。比如在我的

VBF 里,我希望 Functor 可以进行 And, Or 等逻

辑运算,而

Functor 之间只能进行算术运算,Functor 之间只能进行连接运算,而且规则还

不一样

……但是成员函数没有根据类型参数选取不同重载的能力,也就是说.NET 泛型无法

进行特化操作。在

.NET 中具有编译期类型判定的机制只有两个:函数根据参数类型的重载

和用户自定义隐式转换(相当于根据返回类型重载)。我们可以用

Functor<,>类型的静态方

法来实现根据类型参数不同的不同重载。但是静态方法不但要写全类型的名字,还是前缀操
作,使用起来让人甚为不爽,这时就会发现,运算符重载是我们梦寐以求的东西。

Type.op_Operator(x, y) '静态方法
x op y '运算符写法
以上两种是等价的,可以看到运算符重载不仅可以通过

x,y 的类型推测静态方法的调

用主体

Type,还可以将操作转化为中缀写法

——比后缀更适合表现二元运算。既然这么完

美,我们能不能这样写呢?

Class Functor(Of T, U)
    Public Shared Operator And( _
        x As Functor(Of T, Boolean), y As Functor(Of T, Boolean)) _
        As Functor(Of T, Boolean)
    End Operator
End Class
很遗憾,这样会编译错误。作为运算符重载过程,其参数至少有一个必须是定义运算符