C# 接口如何在内部工作? 在C++中,接口与C++具有不同的纯虚函数或java。

C# 接口如何在内部工作? 在C++中,接口与C++具有不同的纯虚函数或java。,c#,C#,在C语言中,与其他主要编译语言不同,接口中的方法不像虚拟函数,这意味着我们不能重写它们 所以我假设在这种情况下,接口甚至不包含vtable 如果没有这个或任何指向函数地址的东西,C中的接口如何在内部知道要调用的指定方法在哪里?无法重写“Foo”的原因是“Root”没有将其标记为虚拟。若将其标记为虚拟,则其工作方式与任何其他虚拟方法类似,并且可以根据需要从子级重写。默认情况下,您可以将C#视为密封接口方法实现。事实上,任何东西都是用C#默认密封的(当然,除了终结器) 与Java这样的语言相比,Ja

在C语言中,与其他主要编译语言不同,接口中的方法不像虚拟函数,这意味着我们不能重写它们

所以我假设在这种情况下,接口甚至不包含vtable


如果没有这个或任何指向函数地址的东西,C中的接口如何在内部知道要调用的指定方法在哪里?

无法重写“Foo”的原因是“Root”没有将其标记为虚拟。若将其标记为虚拟,则其工作方式与任何其他虚拟方法类似,并且可以根据需要从子级重写。默认情况下,您可以将C#视为密封接口方法实现。事实上,任何东西都是用C#默认密封的(当然,除了终结器)

与Java这样的语言相比,Java默认情况下所有实例和非私有函数都是虚拟的


这并没有回答接口在内部是如何工作的,但这与CLR有关,而与C#无关。基本上,CLR生成特定于接口函数的每个调用站点的代码,该调用站点根据对象查找它应该调用的接口函数的地址(非常类似于正常的虚拟分派)。当然,静态调用可以在函数不是虚拟函数时执行,就像您的情况一样(如果我们引用了
Child
Root

在上面的示例中,
Root
实现IMyInterface并公开在
IMyInterface
中定义的特征。在一个完全不同的注释中,
Child
继承了所有
Root
的实现,并且大多数都公开了一组相同特性的超集

事实上,如果使用explisit接口实现(将其命名为
IMyInterface.Foo
),您可以覆盖
Child
中的
Foo
,也可以重新实现

因此,您可以:

    interface IMyInterface 
{
    void Foo();
}
class Root : IMyInterface 
{
    public virtual void Foo() {  } 
}

class Child : Root
{
    public override void Foo() { } 

       void IMyInterface.Foo() { } 

}

关于:

如果没有这个或任何指向函数地址的东西,你怎么办 C#中的接口知道要调用的指定方法的位置, 内部

你的答案是: 或者在非常推荐的书CLR via C中#


需要记住的重要一点是:.Net接口与继承无关,您可以通过重新实现来强制重写任何接口方法。您可以,但要访问该方法,您仍然需要先显式转换为接口类型,然后再调用该方法。这一行
,事实上,在C#
中,默认情况下任何东西都是密封的,这有点令人困惑。我可以解释一下。我对我的答案做了修改。基本上,我将其与Java进行比较,Java默认情况下函数是虚拟的;我对Java知之甚少;所以这句话让我有点困惑:)它们在运行时是动态绑定的。对于这段代码,编译器会给你一个很大的警告,很明显你弄错了。也许是你。当然可以重写它们,只需将实现方法声明为virtual。@HansPassant“它们在运行时是动态绑定的”,这通常是一个不正确的语句。c#不是一种动态语言,至少在这方面不是。绑定是以编译时已知的定义良好的方式完成的。不,CLR是在运行时完成的。编译器仅在IL中表示契约。@HansPassant 1。在大多数情况下,您是对的,因为实际的“绑定”发生在JIT编译期间。2.除了可以通过几种方式将C#编译成机器代码之外,所有这些都将在编译时发生。3.通常,当人们在编程环境中说“动态”时,他们指的是“动态编程语言”的行为方式。从这个意义上说,如果你从C#语义的角度来看,它没有任何动态性。在语义学意义上,它和C++虚拟方法一样具有动态性。我很感激。这是另一个:
    interface IMyInterface 
{
    void Foo();
}
class Root : IMyInterface 
{
    public virtual void Foo() {  } 
}

class Child : Root
{
    public override void Foo() { } 

       void IMyInterface.Foo() { } 

}