【发布时间】:2012-07-09 22:26:49
【问题描述】:
在 C# 中使用 delegate 关键字时,C# 编译器会自动生成一个派生自 System.MulticastDelegate 类的类。
这个编译器生成的类也包含 3 个方法:Invoke, BeginInvoke and EndInvoke。
所有这三个方法都标记为public virtual extern,但有趣的是类本身标记为sealed。
在密封类中定义的虚拟方法不仅违反直觉,而且在 C# 中实际上是非法的。
所以我的问题是,这是否有特定的原因,或者它只是在记住一些假设的未来增强的情况下所做的那些无害的事情之一?
编辑 1:
原因可能是强制使用“callVirt”IL 操作码而不是“call”,以便在尝试执行这三种方法中的任何一种之前,CLR 始终检查委托对象是否为空?虽然我不明白为什么 delegate 在这方面应该是一个特例。
强制使用callvirt 也不会影响性能(尽管可能微不足道)
编辑 2:
添加了 CIL 标记,事实证明 C# 定义委托的方式实际上是由 CIL 标准强制执行的。标准规定(以下不是全文)
委托应具有 System.Delegate 的基本类型。代表应 被宣布密封,并且代表唯一的成员是 此处指定的前两种或所有四种方法。这些 方法应声明为运行时和管理。他们不得有 主体,因为该主体应由 VES 自动创建。其他 委托上可用的方法是从类继承的 基类库中的 System.Delegate。委托方法是:
- 实例构造函数
- Invoke 方法应该是虚拟的
- BeginInvoke 方法(如果存在)应为虚拟
- EndInvoke 方法应为虚拟
所以这绝对不是编译器过程的副作用,或者类似于其他有趣的编译器输出。
如果标准强调某事,那一定是有充分的理由和理由。
那么现在的问题是,为什么 CIL 代表标准同时强调密封和虚拟?
问题在这里吗?:
他们不应该有身体,因为身体应该由 VES 自动创建。
它们是否被标记为虚拟,以便在调用这些方法时可以执行 VES/CLR 生成的主体?
【问题讨论】:
-
不要忘记,在 C# 中无效的内容在 IL 中可能完全有效 - 目前还有其他实例,这可能是另一个。但是对于有趣的发现 +1。
-
我用 ILDasm 进行了尝试,并且在 IL 中将 override 关键字转换为 virtual。
-
@MBen 是的,但是对于 C# 生成的委托类,没有相应的基类方法可以覆盖。因此这里的虚拟关键字不是“覆盖”的结果:)