抽象类的 C# 接口继承

Posted

技术标签:

【中文标题】抽象类的 C# 接口继承【英文标题】:C# Interface Inheritance to Abstract class 【发布时间】:2013-01-09 03:07:58 【问题描述】:

假设我有一个如下定义的接口:

public interface IFunctionality

    void Method();       

我为一个抽象类实现了这个接口,如下所示:

public abstract class AbstractFunctionality: IFunctionality

    public void Method()
    
        Console.WriteLine("Abstract stuff" + "\n");
           

我有一个从抽象类继承的具体类,如下所示:

public class ConcreteFunctionality: AbstractFunctionality

    public void Method()
    
        Console.WriteLine("Concrete stuff" + "\n");
    

现在我有以下代码,

ConcreteFunctionality mostDerived = new ConcreteFunctionality();
AbstractFunctionality baseInst = mostDerived;
IFunctionality interfaceInst = mostDerived;
mostDerived.Method();
baseInst.Method();
interfaceInst.Method();

执行这些东西后我得到的输出如下。

Concrete stuff
Abstract stuff
Abstract stuff

但是我一直期望输出在所有三种情况下都是“具体的东西”,因为我在这里所做的是将ConcreteFunctionality 的引用分配给AbstractFunctionalityIFunctionality 类型的变量。

内部发生的事情。请澄清。

【问题讨论】:

这可能会澄清一些事情:***.com/questions/392721/… “它是隐藏的,而不是被覆盖的”——一个很好的口头禅。 (但你的编译器应该提到这一点;你的警告是否被过滤掉了?) 【参考方案1】:

这里:

public class ConreteFunctionality:AbstractFunctionality

    public void Method()
    
        Console.WriteLine("Concrete stuff" + "\n");
    

...您没有覆盖 existing 方法。您正在创建一个 new 方法,该方法 隐藏 现有方法。 (如果你真的想要这种行为,你也应该得到一个警告,建议使用new 修饰符。)接口是在AbstractFunctionality 中实现的,所以接口映射表引用了该类中的方法。

现在如果你重新实现接口:

public class ConcreteFunctionality : AbstractFunctionality, IFunctionality

...然后接口映射将引用ConcreteFunctionality 中的方法,您将通过 interface 获得您期望的调用行为(即您的第三次调用),但您' d 仍然会在 AbstractFunctionality 中为您的第二次调用获取实现。

AbstractFunctionality 中的方法设为虚拟方法,并在ConcreteFunctionality 中覆盖它,通常会更干净、更安全。这样它将在所有情况下都使用ConcreteFunctionality 实现。

【讨论】:

这不会给出预期的行为,因为第二次调用仍将通过抽象实现。 @JonHanna:我没有注意到第二次调用会使用具体版本的期望。将编辑。【参考方案2】:

您需要将类定义为:

public abstract class AbstractFunctionality:IFunctionality

    public virtual void Method()
    
        Console.WriteLine("Abstract stuff" + "\n");
           


public class ConreteFunctionality:AbstractFunctionality

    public override void Method()
    
        Console.WriteLine("Concrete stuff" + "\n");
    

由于您没有在 ConreteFunctionality 中覆盖 Method(),因此运行时环境会执行与 AbstractFunctionality 对象关联的 Method(),因为它不能在此处应用动态多态性。引入virtualoverride 使得运行时环境可以在子类中执行被覆盖的方法。

【讨论】:

不错的答案;但我会介绍术语“隐藏”,它描述了 OP 的原始代码,并注意隐藏没有“新”关键字的方法会导致编译器警告。【参考方案3】:

您缺少 virtualoverride 关键字。没有它,您将无法获得虚函数。

您可以将 AbstractFunctionality 中的 Method 标记为 virtual,并将 ConreteFunctionality 中的 Method 标记为 override。正如 mihirj 所展示的那样。

在 -Why are C# interface methods not declared abstract or virtual?

中解决了类似的问题

【讨论】:

以上是关于抽象类的 C# 接口继承的主要内容,如果未能解决你的问题,请参考以下文章

编写高质量代码改善C#程序的157个建议——建议102:区分接口和抽象类的应用场合

C#中接口和抽象类的区别

C# 类 - 接口 Interface

scala 抽象类和trait的区别

接口和抽象类

接口和抽象类的区别