为什么C#接口方法没有声明为抽象或虚拟的?

问题描述 投票:107回答:6

接口中的C#方法在不使用virtual关键字的情况下进行声明,并且在派生类中被覆盖,而在不使用override关键字的情况下被重写。

这是否有原因?我认为这只是一种语言上的方便,显然CLR知道如何在后台进行处理(默认情况下方法不是虚拟的),但是还有其他技术原因吗?

这是派生类生成的IL:

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

c# methods interface abstract virtual-functions
6个回答
141
投票

对于接口,添加abstract甚至是public关键字都是多余的,因此您可以省略它们:

interface MyInterface {
  void Method();
}

在CIL中,方法标记为virtualabstract

((请注意,Java允许将接口成员声明为public abstract

对于实现类,有一些选项:

Non-overridable:在C#中,类未将方法声明为virtual。这意味着它不能在派生类中被覆盖(只能是隐藏的)。在CIL中,该方法仍然是虚拟的(但是密封的),因为它必须支持有关接口类型的多态性。

class MyClass : MyInterface {
  public void Method() {}
}

Overridable:在C#和CIL中,方法均为virtual。它参与多态调度,可以被覆盖。

class MyClass : MyInterface {
  public virtual void Method() {}
}

Explicit:这是类实现接口的一种方法,但不提供类本身的公共接口中的接口方法。在CIL中,该方法将为private(!),但仍可以从类外部通过对相应接口类型的引用进行调用。显式实现也是不可覆盖的。这是可能的,因为有一个CIL指令(.override)将私有方法链接到它正在实现的相应接口方法。]

[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中,您甚至可以在实现类中为接口方法名称加上别名。

[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
}

现在,考虑这个奇怪的情况:

interface MyInterface {
  void Method();
}
class Base {
  public void Method();
}
class Derived : Base, MyInterface { }

如果BaseDerived在同一程序集中声明,则即使Base::Method未实现该接口,编译器也会将Base设为虚拟且密封(在CIL中)。

如果BaseDerived位于不同的程序集中,则在编译Derived程序集时,编译器将不会更改其他程序集,因此它将在Derived中引入一个成员,该成员将明确实现MyInterface::Method会将呼叫仅委派给Base::Method

因此,您看到,每个

接口方法实现必须支持多态行为,因此即使编译器必须经过箍才能做到这一点,也必须在CIL上将其标记为虚拟。

73
投票

此处通过CSharp第三版从CLR引用Jeffrey Ritcher


12
投票

是的,就运行时而言,接口实现方法是虚拟的。这是一个实现细节,它使接口正常工作。虚拟方法在类的v表中获取插槽,每个插槽都有一个指向虚拟方法之一的指针。将对象强制转换为接口类型会生成一个指向实现接口方法的表部分的指针。现在,使用接口引用的客户端代码将看到第一个接口方法指针,该指针与接口指针等距偏移量0。


4
投票
在大多数其他已编译的代码环境中,接口被实现为vtables-指向方法主体的指针列表。通常,实现多个接口的类将在其内部编译器生成的元数据中的某处具有接口vtable的列表,每个接口一个vtable(以便保留方法顺序)。这也是通常通常实现COM接口的方式。

0
投票
它们不是虚拟的(就我们的看法而言,如果不是基于底层实现的(密封的虚拟)-可以在这里阅读其他答案并自己学点东西:-)

0
投票
接口是比类更抽象的概念,当您声明一个实现接口的类时,您只是在说:“该类必须具有来自接口的这些特定方法,而与[[static
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.