为什么可以在基类中实现一个接口方法?

在我的项目中,我发现了一个奇怪的情况,在C#中似乎完全有效,因为我没有编译时错误。

简单的例子看起来像这样:

using System; using System.Collections.Generic; namespace Test { interface IFoo { void FooMethod(); } class A { public void FooMethod() { Console.WriteLine("implementation"); } } class B : A, IFoo { } class Program { static void Main(string[] args) { IFoo foo = new B(); foo.FooMethod(); } } } 

这样的代码编译。 但是请注意, A不是IFooB不实现IFoo方法。 在我的情况下,意外(重构后), A有相同的签名的方法。 但为什么要知道如何实现IFoo接口的FooMethod呢? 甚至不知道IFoo存在。

对我来说这样的devise是危险的。 因为每次我实现一些接口,我应该检查这个接口中的每个方法是否与基类方法“干涉”。

如果这是“纯粹的C#function”? 这叫什么? 我错过了什么吗?

对于接口中的每个成员,编译器只需查找一个显式实现(如果有的话),然后是一个公共实现( 隐式实现),也就是公共API中匹配接口签名的方法。 在这种情况下, A.FooMethod()看起来像是一个公共实现的良好匹配。 如果B对这个select不满意,它可以是new的方法,或者使用一个明确的实现; 后者将是首选:

 void IFoo.FooMethod() { /* explicit implementation */ } 

这里的关键词是implements 。 你的基类,虽然它不知道任何有关IFoo的方法签名已被声明,它在你的类层次结构中的某个接口实现了方法。

所以当你在派生类中实现IFoo时,它已经在类结构中实现了方法签名,因此不需要再次实现它。

如果你有这个:

 interface IFoo { void FooMethod(); } class A { private void FooMethod(){} } class B : A, IFoo { } 

在这种情况下,你需要实现IFoo ,因为IFoo结构在实现的地方是不可访问的,正如Mark所说的那样。 您可以通过执行IFoo.FooMethod()来隐式实现接口,以确保您有实现,尽pipe在层次结构中已经定义了适当的方法签名。

你在评论中说,

A没有实现IFoo类中实现IFoo实际上有意实现IFoo可能性有多大?

那么, A创作时A的作者是什么都没有关系。 B的作者必须对Binheritance自A并且实现IFoo的事实承担责任。 B的作者应该考虑B的定义的后果

你也说

在我的意外(重构后) A有相同的签名的方法

这表明这种情况是在AB写完之后出现的。 在这种情况下,情况会发生变化:编辑从*(如Ainheritance的类时,编辑器有责任检查编辑对所有inheritance类的影响

为了实现一个接口,一个类只需要(a)声明它正在实现那个接口(比如你的类B),并且(b)提供接口中定义的所有方法的实现,直接或间接地通过基类(比如你的B类)。

该function称为inheritance 。 如果你不喜欢这个devise,就不要使用它。 许多人不喜欢inheritance,所以你也可能。 inheritance的定义是基类的所有成员也是派生类的成员。 所以没有任何编译器错误。 因此派生实施IFoo提供的合同。 这是基础class成员,满足这个要求。

它的优点在于,你可以通过一个基本的function (虚拟)来实现一个接口,如果一个Derived预期会有不同的performance,那么这个接口可以被重写。

接口不被inheritance,接口被实现。 因此,当你从一个接口派生一个类,就意味着

嘿界面,你会发现一个方法在这里实现你提供的方法签名。

由于基类具有方法的实现,所以在接口中定义的方法签名相同,不会有问题。

即使你编写包含相同方法签名的第二个接口,它仍然可以工作。

 interface IFoo2 { void FooMethod(); } class B : A, IFoo, IFoo2 { } 

第13.4.4节。 的C#规范的状态:

类或结构C的接口映射为C的基类列表中指定的每个接口的每个成员定位实现。确定特定接口成员IM(其中I是声明成员M的接口)的实现通过检查每个类或结构S, 从C开始,为C的每个后续基类重复,直到find匹配:

所以看起来这是一个很好定义的行为,因为在B没有findFooMethod的正确实现,所以在其基类A上执行search,其中find具有匹配签名的方法。 这甚至在规范的相同部分中明确指出:

基类的成员参与接口映射。 在这个例子中

 interface Interface1 { void F(); } class Class1 { public void F() {} public void G() {} } class Class2: Class1, Interface1 { new public void G() {} } 

Class1中的方法F用于Interface1的Class2实现中。

B执行IFOOBAinheritance,所以它看起来像这样:

 class B : IFoo //Notice there is no A here. { public void FooMethod() { Console.WriteLine("implementation"); } } 

从上面的代码中可以明显看出, B正在实施IFoo ,没有什么特别的。

虽然推测为什么C#的创build者做了他们所做的事情并不是特别有帮助,虽然我不喜欢这个特殊function,但是我怀疑它的原理的一部分,因为它没有其他好的语法指定一个接口应该由一个已经存在的基类方法实现。 要求派生类必须定义的方法什么都不做,只能链接到基类实现看起来很丑。

话虽如此,我认为通过提供一种语法来明确附加一个接口成员到一个类成员,C#能够解决一般问题(链接到其他成员的接口方法是丑陋的),而不是使用自动绑定语义来处理一个特定的情况,但需要在更常见的情况下进行链接(通过受保护的虚拟方法来实现接口):

受保护的虚拟IFoo_Method(int a,int b,int c){…}

IFoo.Method(int a,int b,int c){IFoo_Method(a,b,c); }

虽然JITter可能会发现IFoo_Method调用应该被内联,但实际上并不需要。 宣称受保护的方法IFoo_Method应该被视为IFoo.Method的实施似乎更为清晰。方法。

“但是为什么要知道如何实现IFoo接口的FooMethod?甚至不知道IFoo的存在。

A不需要知道接口IFoo的存在。 它没有正确实施FooMethod的责任。 显然,碰巧实现了与IFoo接口方法FooMethod具有相同签名的方法。

它是B实现FooMethod的责任,因为它实现了IFoo接口。 但是由于B已经有一个名为FooMethod(从Ainheritance)的方法,所以不需要明确地实现它。 如果一个inheritance的方法没有完成它的工作,B可以重新创build这个方法并编写它自己的实现。