C# 为什么可以在基类中实现接口方法?
在我的项目中,我发现了一种奇怪的情况,这种情况在C#中似乎完全有效,因为我没有编译时间错误 简化的示例如下所示:C# 为什么可以在基类中实现接口方法?,c#,interface,C#,Interface,在我的项目中,我发现了一种奇怪的情况,这种情况在C#中似乎完全有效,因为我没有编译时间错误 简化的示例如下所示: using System; using System.Collections.Generic; namespace Test { interface IFoo { void FooMethod(); } class A { public void FooMethod() {
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
不是IFoo
,B
没有实现IFoo
方法。在我的例子中,(在重构之后),A
的方法具有相同的签名。但是为什么A
应该知道如何实现IFoo
接口的foodmethod
A
甚至不知道IFoo
的存在
对我来说,有这样的设计是危险的。因为每次实现某个接口时,我都应该检查该接口中的每个方法是否“干扰”基类方法
如果这是“纯C#特性”?它叫什么?我遗漏了什么吗?这里的关键词是
实现
。您的基类,尽管它对IFoo
一无所知,但已经声明了方法签名,它在类层次结构中的某个地方实现了接口中的方法
因此,当您在派生类中实现IFoo
时,它已经在类结构中实现了方法签名,因此不需要再次实现它
如果你有这个:
interface IFoo
{
void FooMethod();
}
class A
{
private void FooMethod(){}
}
class B : A, IFoo
{
}
在这种情况下,您需要实现
IFoo
,因为IFoo
结构在实现时是不可访问的,正如Mark所说。您可以通过执行IFoo.FooMethod()
隐式实现该接口,以确保在层次结构中已定义了适当的方法签名的情况下仍有实现。要实现接口,类只需(a)声明它正在实现该接口(如您的类B所做的),以及(B)为接口中定义的所有方法提供实现,可直接或间接通过基类(如您的类B)提供实现。对于接口中的每个成员,编译器只需查找显式实现(如果有),然后查找公共实现(隐式实现),即,公共API上与接口签名匹配的方法。在本例中,A.FooMethod()
看起来与公共实现非常匹配。如果B
对该选择不满意,它可以new
方法,或者使用显式实现;后者最好是:
void IFoo.FooMethod() { /* explicit implementation */ }
该特性称为继承。如果你不喜欢这个设计,就不要使用它。很多人不喜欢继承,所以你也可以。继承的定义是,基类的所有成员都是派生类的成员。因此没有任何编译器错误。因此,派生函数实现了IFoo
提供的契约。它是满足此要求的基类成员
它的美妙之处在于,您可以通过基本功能(虚拟)来实现接口,如果派生功能的行为预期不同,则可以覆盖基本功能。接口不是继承的,而是实现的。因此,当您从接口派生类时,它意味着 嘿接口,您将在这里找到一个实现该方法的方法 你提供的签名 由于基类具有方法的实现,并且在接口中定义了相同的方法符号,因此不会出现问题 即使您编写第二个包含相同方法符号的接口,它仍然可以工作
interface IFoo2
{
void FooMethod();
}
class B : A, IFoo, IFoo2
{
}
B
执行IFOO
B
继承自A
,因此它实际上看起来像这样:
class B : IFoo //Notice there is no A here.
{
public void FooMethod()
{
Console.WriteLine("implementation");
}
}
(从上述代码中)可以清楚地看出,B
正在实现IFoo
,没有什么特别之处。第13.4.4节。C#规范中规定:
类或结构C的接口映射为C的基类列表中指定的每个接口的每个成员定位一个实现。特定接口成员I.M的实现,其中I是声明成员M的接口,通过检查每个类或结构来确定,从C开始,对C的每个连续基类重复,直到找到匹配项:
因此,这似乎是定义良好的行为,因为在B
中找不到foodmethod
的正确实现,因此在其基类a
上执行搜索,其中找到了具有匹配签名的方法。规范的同一节甚至明确指出了这一点:
基类的成员参与接口映射。在这个例子中
Class1中的方法F用于Class2接口1的实现
你在评论中说,
在IFoo
未实现的IFoo
类中编写foodmethod
实现的人实际打算实现IFoo
的可能性有多大
嗯,A
的作者在A
创作时的想法并不重要。B
的作者必须对B
既继承了A
又实现了IFoo
这一事实负责由B
的作者来考虑B
定义的后果
你也说
在我的例子中(重构后)A
的方法具有相同的签名
表明这种情况是在
A
和B
都被编写之后发生的。在这种情况下,情况会发生变化:编辑从*继承的类(例如a
)时,编辑人员有责任检查编辑对所有继承类的影响,而不是特别的
interface Interface1
{
void F();
}
class Class1
{
public void F() {}
public void G() {}
}
class Class2: Class1, Interface1
{
new public void G() {}
}