Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/270.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 为什么可以在基类中实现接口方法?_C#_Interface - Fatal编程技术网

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

C# 为什么可以在基类中实现接口方法?,c#,interface,C#,Interface,在我的项目中,我发现了一种奇怪的情况,这种情况在C#中似乎完全有效,因为我没有编译时间错误 简化的示例如下所示: using System; using System.Collections.Generic; namespace Test { interface IFoo { void FooMethod(); } class A { public void FooMethod() {

在我的项目中,我发现了一种奇怪的情况,这种情况在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
不是
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() {}
}