的类型。在编译器看来,必须是
Functor(Of T, U),两个类型参数都必须是该泛型类定义的。
就在我对此大感抱怨时,我偶然在
C#编译器的源代码(见 Rotor)中看到了它识别运算符
的规则,其中并没有这些限制,只有两条规则
——方法必须是静态的,特定名称的方法;
方法必须带有
specialname 属性。那么我们完全可以骗过编译器,不用它提供的 Operator 关
键字来声明运算符重载过程,而是使用自己编写特定名称的方法,并加以
specialname 的手
法来打造运算符重载过程:
Imports System.Runtime.CompilerServices
Class Functor(Of T, U)
_
Public Shared Function op_BitwiseAnd( _
x As Functor(Of T, Boolean), y As Functor(Of T, Boolean)) _
As Functor(Of T, Boolean)
End Function
End Class
System.Runtime.CompilerServices.SpecialNameAttribute 是一个指示编译器为声明成员添
加
specialname 的特殊属性,C#和 VB 编译器都支持。op_BitwiseAnd 是 VB 和 C#等语言所识
别的与操作运算符过程名称。这样写完以后编译成类库,再以引用
DLL 的方式引用它,你
就会看到编译器将他识别成了我们要的运算符重载过程。当你在
Functor 这样的类型上使用
And 操作时,编译器会告诉你不支持该运算符,仅在 Functor 上才能进行这一操作,编译错
误信息准确无误,真是太棒了。
在我们结束前,我们还可以看看如此手工打造还能突破哪些编译器人为的限制:
可重载
Protected 和 Private 的运算符(尽管这样做几乎没有意义)
可不成对重载比较运算符(
=, >, >=, <=, <, <>)
可以让移位运算符的第二个操作数不是
int(>>和<<样子很好看,但是有了这个限制我
们就不能拿它来干别的事情,现在好了)
可以在
C#中重载仅 VB 支持的运算符,也可以在 VB 中重载仅 C#支持的运算符(当然
要到对方语言中才能生效)
可以让用户自定义显式转换支持泛型类型参数之间更加神奇的写法
用了这种手法,似乎还可以重载诸如
operator+(int, int)之类的运算符,但它们并不能生
效。
.NET 语言编译器中每一项特性,都可能有隐藏在其表面之下的深层次用途。善加研究
后常能发现原来所认识不到的功能。我当然不是在推荐大家乱用运算符重载,只是一种思考,
一种新的灵感。