C#hack:接口和抽象类之间的低级别差异

这是一个关于C#基础知识的哲学问题:我想知道完全抽象类可以模拟接口的接近程度。 假设我们有以下界面:

public interface INativeInterface { void PerformAction(); String Property { get; set; } } 

以及抽象类:

 public abstract class ISimulatedInterface { public abstract void PerformAction(); public abstract String Property { get; set; } } 

他们有很多共同点,不是吗? 我所知道的差异是:

  • 多重inheritance不适用于抽象类
  • 显式实现不适用于抽象类

使用reflection或类似的东西可以跳过这些限制吗?

我意识到接口和抽象类在root中是不同的:接口声明了“ 可以表现得像 ”的条件,抽象类 – “ 是一种 ”,但即使这似乎是如此接近以至于这些实体之间的低级别差异要讨论的。 这个问题甚至可以听起来像“你会用C ++创建一个接口”。

使用reflection或类似的东西可以跳过这些限制吗?

在摘要中,抽象类和接口是公共语言运行时级别的不同概念。 因此,在C#中既不可能,因为最终限制为CLR的边界。

我想知道完全抽象的类可以模拟接口的接近程度。

它是可行的,但需要来自底层执行环境(无论是物理的还是管理的)的支持(或“允许”)。

在过去,我设计了一种语言,完全取代了接口的抽象类。 是的,它确实支持这种“接口”的多重inheritance。 但是,实施的特点可能不值得付出努力。 主要的“低级别差异”是inheritance的抽象类的内部嵌入式实例必须保留在实现类的实例中,并且必须保持this指针链。 不用说,这是一次快乐的经历:-)

所以,如果我理解你的问题,你有两个相关的问题。

第一个是“抽象类和接口之间有什么区别”; 第二个是,“在C#中,我可以通过使一个没有具体方法的抽象类表现得像一个接口来绕过差异吗?”。

第一个问题在@Todd Schiller的链接中得到了很好的回答。

第二个问题更复杂。

您可能可以创建构建时任务,以将所有抽象类转换为接口而无需具体实现。 我从未尝试过 – 因为我认为这样做没有任何好处,还有很多很多缺点。

最大的缺点是您的代码变得更难以调试和维护。 开发人员学习何时创建抽象类,何时创建接口; 这是一个既定的,共同商定的习语。 开发代码库的新开发人员将会学习很多新东西 – 并且引入一种思考接口和抽象类的新方法将使该过程更加困难和更长久。

在调试应用程序时,在源代码中看到抽象类的开发人员 – 但在运行时代码中看到它实际上是一个接口 – 可能会感到困惑,并花时间尝试找出发生这种情况的原因,而不是追查真正的错误。

就我所见,没有明显的好处。

对我来说,它真的归结为他们的能力。 接口永远不会为其任何操作提供实现; 它只承诺使用它的人必须提供一些东西。 抽象类可以为其任何操作提供实现,这些操作可以由其子类自行决定覆盖。 不,你永远不可能通过反思覆盖这些限制,因为它们是语言本身的核心。

至于使用抽象类代替接口,它再次归结为您需要完成的任务。 如果需要提供一些基本实现,则必须使用抽象类 – 否则,请使用接口。

您已经提到的其他一些差异。 您可以在C#中实现多个接口,但是您只能从单个类(抽象或其他)派生。

它可能是OOPS哲学背景下的热门话题。我们知道它几乎没有技术差异,比如接口没有构造函数,inheritance类必须实现所有方法等,但我喜欢用现实场景来讨论它。 实际上我认为接口是一个对象与其消费者之间的契约。但是抽象类不是契约,即使两者都可以用来实现“liskov替换原则”。 我想列出现实生活中的两种情况..

1.)想象一个绘图应用程序,它可能包含形状,矩形,正方形等。这里的形状可以是抽象类或接口类型。 但是如果我需要确保应用程序中的每个对象在实例化时都必须具有状态。 我无法通过接口实现此function,因此接口无法保持对象的状态。

2.)如果我的形状共享共同的值(静态值),我无法使用接口实现,所以我认为抽象类可以保持状态和行为

但考虑到界面是一个关于行为的协议,看起来是一个真实的例子,动物和鸟类,这两个对象都有一些相似的行为,但我们不能说它们有共同的属性,鸟类和动物都可以走路,哭泣,吃饭,执行这些行动完全不同。 在我们的编程接口中,在您只需要协议而不需要任何状态的情况下,它是理想的候选者。 好消息是消费者对象可以取代满足该协议的任何其他对象,DI就是一个最好的例子。