一个继承另一个类的类会继承那个类所继承的类/接口吗?

7

我有两个类:

public class Question : IDisposable, IEquatable<Question>
{
}

public class SessionQuestion : Question, IDisposable, IEquatable<SessionQuestion>
{
}

Question 继承了 IDisposableIEquatable 接口,那么 SessionQuestion 会不会隐式地继承那些接口呢?


是的。试试自己做,输入 SessionQuestion s = new SessionQuestion(); 然后 if (s is IDisposable) - dmeglio
3
注意:不要混淆。由于继承关系,SessionQuestionQuestion 继承了 IEquatable<Question> 接口。但是,SessionQuestion 还实现了与 IEquatable<Question> 不同的 IEquatable<SessionQuestion> 接口。因此,您可以省略对 SessionQuestionIDisposable 接口进行说明(它已经被从 Question 继承),但需要保留 IEquatable<SessionQuestion>(因为 Question 没有实现这个接口)。 - user2819245
@elgonzo 很好的观点! - dmeglio
作为后续问题,可以将以下程序相关的内容从英语翻译成中文。感谢您的帮助。 - Will
@Will,我刚才扩展了我的答案,以说明当一个类从其基类继承接口并同时提供该接口成员的一些显式实现时可能发生的一些奇怪而有趣的陷阱。享受吧 :-D - user2819245
1
@elgonzo 是对的。但请注意,在未封闭的类上实现 IEquatable<> 可能是一个不好的主意。更多详情请参见 Should IEquatable<T>, IComparable<T> be implemented on non-sealed classes? - Jeppe Stig Nielsen
3个回答

6
答案是“是”,接口是可以被继承的。但是,你是否可以省略将接口定义包含在一个类中取决于该类是否想要将某些接口成员作为显式接口实现explicit interface implementations
让我们以这个非常简单(又有点傻)的例子为例:
public interface IMyInterface
{
    void foo();
}

public class A : IMyInterface
{
    public void foo()
    {
        Console.Out.WriteLine("A.foo() executed");
    }
}

public class B : A, IMyInterface
{
    void IMyInterface.foo()
    {
        Console.Out.WriteLine("B.foo() executed");
    }
}

由于B希望将foo()方法作为显式接口实现,因此在其类定义中必须指定IMyInterface接口--即使类A已经实现了该接口。在这种情况下,从基类继承接口声明是不够的。

如果B类没有显式接口实现,则B类不需要再次指定接口(在这个小例子中是IMyInterface)。


从基类继承接口并具有某些接口成员的显式接口实现可能会导致令人惊讶的效果,最坏的情况下可能会导致损坏/错误的软件。

如果您执行以下代码序列:

A obj = new A();
obj.foo();
IMyInterface x = obj;
x.foo();

输出结果将会是

执行 A.foo()
执行 A.foo()


然而,现在让我们使用一个类型为 B 的对象,但是保持代码完全相同:

B obj = new B();
obj.foo();
IMyInterface x = obj;
x.foo();

输出结果会略有不同:
A.foo()执行了 B.foo()执行了
为什么会这样呢?请记住,类B继承自类A的foo()方法实现。因此,调用obj.foo()仍将执行继承的foo()方法。
那么为什么x.foo()不会调用类A提供的foo()实现呢?或者,为什么obj.foo()不会调用类B给出的foo()实现呢?
因为x是类型为IMyInterface的变量,因此在调用x.foo()时,由类型B的对象提供的foo()方法的显式接口实现优先。变量obj不是IMyInterface类型,因此obj.foo()不会调用foo()方法的显式接口实现。
由于这些令人惊讶的结果,我们很容易理解为什么对于已经由基类实现的接口来说,显式接口实现在大多数情况下都不是一个好主意。正如俗话所说:“你能做到并不意味着你应该这样做”。

1
这里的技术术语是接口重新实现。一个不那么令人困惑的替代方案可能是通过一个public ***virtual***方法/属性等在基类中实现接口。 - Jeppe Stig Nielsen

3
当然。
实际上,.NET Framework并不是一个扁平的类层次结构。随便选择一个类并查看。你会发现它派生自一个派生自一个类,依此类推。
接口也像普通类一样被继承到子孙级别。
至于你需要实现的成员:如果你在Question中已经实现了它们,那么你当然不需要在SessionQuestion中再次实现它们。

3

当然,你仍需要实现接口定义的所有成员。然而,如果基类包含与接口成员匹配的成员,则基类成员可以作为接口成员的实现工作,你无需手动再次实现它。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接