问题描述
接口中的 C# 方法不使用 virtual
关键字声明,并在派生类中覆盖而不使用 override
关键字.
C# methods in interfaces are declared without using the virtual
keyword, and overridden in the derived class without using the override
keyword.
这是有原因的吗?我认为这只是一种语言方便,显然 CLR 知道如何在幕后处理这个问题(默认情况下方法不是虚拟的),但还有其他技术原因吗?
Is there a reason for this? I assume that it is just a language convenience, and obviously the CLR knows how to handle this under the covers (methods are not virtual by default), but are there other technical reasons?
这是派生类生成的 IL:
Here is the IL that a derived class generates:
class Example : IDisposable {
public void Dispose() { }
}
.method public hidebysig newslot virtual final
instance void Dispose() cil managed
{
// Code size 2 (0x2)
.maxstack 8
IL_0000: nop
IL_0001: ret
} // end of method Example::Dispose
请注意,该方法在 IL 中声明为 virtual
final
.
Notice that the method is declared virtual
final
in the IL.
推荐答案
对于界面来说,添加abstract
,甚至public
关键字都是多余的,所以你省略了它们:
For the interface, the addition of the abstract
, or even the public
keywords would be redundant, so you omit them:
interface MyInterface {
void Method();
}
在CIL中,方法被标记为virtual
和abstract
.
In the CIL, the method is marked virtual
and abstract
.
(注意 Java 允许将接口成员声明为 public abstract
).
(Note that Java allows interface members to be declared public abstract
).
对于实现类,有一些选择:
For the implementing class, there are some options:
不可覆盖:在 C# 中,该类不会将方法声明为 virtual
.这意味着它不能在派生类中被覆盖(仅隐藏).在 CIL 中,该方法仍然是虚拟的(但密封的),因为它必须支持关于接口类型的多态性.
Non-overridable: In C# the class doesn't declare the method as virtual
. That means that it cannot be overridden in a derived class (only hidden). In the CIL the method is still virtual (but sealed) because it must support polymorphism regarding the interface type.
class MyClass : MyInterface {
public void Method() {}
}
Overridable:在 C# 和 CIL 中,该方法都是virtual
.它参与多态调度并且可以被覆盖.
Overridable: Both in C# and in the CIL the method is virtual
. It participates in polymorphic dispatch and it can be overridden.
class MyClass : MyInterface {
public virtual void Method() {}
}
Explicit:这是一个类实现一个接口但不提供该类本身的公共接口中的接口方法的一种方式.在 CIL 中,该方法将是 private
(!) 但它仍然可以从类外部通过对相应接口类型的引用调用.显式实现也是不可覆盖的.这是可能的,因为有一个 CIL 指令 (.override
) 将私有方法链接到它正在实现的相应接口方法.
Explicit: This is a way for a class to implement an interface but not provide the interface methods in the public interface of the class itself. In the CIL the method will be private
(!) but it will still be callable from outside the class from a reference to the corresponding interface type. Explicit implementations are also non-overridable. This is possible because there's a CIL directive (.override
) that will link the private method to the corresponding interface method that it's implementing.
[C#]
class MyClass : MyInterface {
void MyInterface.Method() {}
}
[CIL]
.method private hidebysig newslot virtual final instance void MyInterface.Method() cil managed
{
.override MyInterface::Method
}
在 VB.NET 中,您甚至可以在实现类中为接口方法名称取别名.
In VB.NET, you can even alias the interface method name in the implementing class.
[VB.NET]
Public Class MyClass
Implements MyInterface
Public Sub AliasedMethod() Implements MyInterface.Method
End Sub
End Class
[CIL]
.method public newslot virtual final instance void AliasedMethod() cil managed
{
.override MyInterface::Method
}
现在,考虑这个奇怪的案例:
Now, consider this weird case:
interface MyInterface {
void Method();
}
class Base {
public void Method();
}
class Derived : Base, MyInterface { }
如果 Base
和 Derived
在同一个程序集中声明,编译器将使 Base::Method
虚拟和密封(在 CIL),即使 Base
没有实现接口.
If Base
and Derived
are declared in the same assembly, the compiler will make Base::Method
virtual and sealed (in the CIL), even though Base
doesn't implement the interface.
如果Base
和Derived
在不同的程序集中,编译Derived
程序集时,编译器不会改变其他程序集,所以它将在 Derived
中引入一个成员,该成员将是 MyInterface::Method
的显式实现,它将调用委托给 Base::Method
.
If Base
and Derived
are in different assemblies, when compiling the Derived
assembly, the compiler won't change the other assembly, so it will introduce a member in Derived
that will be an explicit implementation for MyInterface::Method
that will just delegate the call to Base::Method
.
所以你看,每个接口方法的实现都必须支持多态行为,因此必须在 CIL 上标记为虚拟,即使编译器必须通过箍来做到这一点.
So you see, every interface method implementation must support polymorphic behavior, and thus must be marked virtual on the CIL, even if the compiler must go through hoops to do it.
这篇关于为什么 C# 接口方法没有声明为抽象或虚拟?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!