代码之家  ›  专栏  ›  技术社区  ›  Robert Harvey

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

  •  101
  • Robert Harvey  · 技术社区  · 15 年前

    接口中的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
    

    注意,方法是声明的 事实上的 final 在伊利诺伊州。

    6 回复  |  直到 12 年前
        1
  •  149
  •   Jordão    15 年前

    对于接口,添加 abstract ,甚至是 public

    interface MyInterface {
      void Method();
    }
    

    在CIL中,方法被标记为 virtual 摘要 .

    (注意,Java允许声明接口成员 public abstract ).

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

    不可重写 :在C#中,类不会将方法声明为 事实上的 . 这意味着它不能在派生类中被重写(仅隐藏)。在CIL中,该方法仍然是虚拟的(但是是密封的),因为它必须支持关于接口类型的多态性。

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

    可覆盖的 :在C#和CIL中,方法都是 事实上的

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

    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版]

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

    Base Derived 在同一程序集中声明,编译器将 Base::Method 底座

    如果 派生 在编译 派生 派生 这将是一个明确的实现 MyInterface::Method 那就把电话委托给 基::方法 .

    每一个 接口方法实现必须支持多态行为,因此必须在CIL上标记为virtual,即使编译器必须通过一些限制才能做到这一点。

        2
  •  74
  •   Robert Harvey    14 年前

    引用杰弗里里彻从CLR通过CSharp第三版这里

    CLR需要该接口 方法不能标记为虚拟。如果你 编译器将该方法标记为虚拟 方法,编译器将其标记为 方法是虚拟的(并将其保留) 未密封);这允许派生类 重写接口方法。如果 派生类不能重写 重新继承同一接口并可以 为

        3
  •  13
  •   Hans Passant    15 年前

    在我最初的回答中,我所低估的是 属性。它防止派生类重写虚方法。派生类必须重新实现接口、实现方法 阴影 基类方法。这足以实现C语言契约,即实现方法不是虚拟的。

    最终的 属性正在删除。现在允许派生类重写它。

        4
  •  4
  •   dthorpe    15 年前

    不过,在.NET中,接口并不是作为每个类的不同vtable实现的。接口方法通过一个全局接口方法表进行索引,所有接口都是该表的一部分。因此,不必为了实现接口方法而声明虚方法-全局接口方法表可以直接指向类方法的代码地址。

    为了实现接口而声明虚方法在其他语言中也不是必需的,即使在非CLR平台中也是如此。Win32上的Delphi语言就是一个例子。

        5
  •  0
  •   Jason Williams    15 年前

    它们不会覆盖任何东西-接口中没有实现。

    然后由类在契约的范围内实现接口方法—虚拟的或“非虚拟的”(事实证明是密封的虚拟的)。

        6
  •  0
  •   Robert Harvey    6 年前

    接口是一个比类更抽象的概念,当您声明一个实现接口的类时,您只需说“类必须具有接口中的这些特定方法,而不管是什么方法” 事实上的 非虚拟的 , ,只要它具有相同的ID和相同的类型参数”。

    其他支持接口的语言如Object Pascal(“Delphi”)和Objective-C(Mac)也不需要将接口方法标记为virtual和not virtual。

    限制

    我理解你的问题,因为我在Java中看到类似的东西,当一个类方法必须使用“@virtual”或“@override”来确保一个方法是虚拟的。

    推荐文章