抽象类与接口

dev*_*ull 18 c#

我对C#中抽象类的使用有点困惑.在C++中,定义一个继承抽象类的类可以遵循的模板是有意义的.但是,在C#中,Interface不具备相同的用途吗?

确实,抽象类可以具有接口不提供的默认实现.因此,如果实现不需要包含在基类中,那么最好选择接口吗?

Ada*_*son 20

我仍然想提供一个接口的默认抽象实现,假设它是一个实质性的接口(它是有道理的).你永远不知道什么时候你可以在接口上添加一些东西,这个接口有一个简单的默认实现,可以包含并免费提供给从抽象基类继承的任何人.

  • @CodeInChaos:虽然扩展方法*可以*解释抽象类与接口的一些用例,但它们不是替代品.扩展方法不允许多态,要求它们的声明命名空间要么与使用代码相同,要么在显式的"using"(VB"Includes")声明中,并且不能访问任何非公共成员.扩展方法允许您更轻松地定义您可以在类*之外复制*的功能. (3认同)

Chr*_*isF 19

这篇CodeProject文章有很多关于两者之间差异的信息,包括比较和对比每个特征的表格.

接口定义了类之间的契约 - 类相互调用的方式.类可以实现多个接口,但只能从一个抽象类继承.


Ed *_* S. 10

确实,抽象类可以具有接口不提供的默认实现.因此,如果实现不需要包含在基类中,那么最好选择接口吗?

是的:).如果在基类中实现一些对所有固有类通用的方法是有意义的,那么你应该使用一个抽象类.如果基类只用于定义接口,但继承的类之间没有通用逻辑,则使用接口.

  • 它很少"或 - 或".很多时候,你会发现一个健康的混合类与一个共同的祖先混合了不同的祖先类实现相同的界面. (4认同)
  • @Ed:我得到的并不是你必须在两者之间作出选择.通过同时获得最大的灵活性(以及相应的最高维护成本).您定义接口,然后创建一个抽象类,提供接口的默认实现.这样可以方便继承层次结构和界面的灵活性. (3认同)

Teb*_*ebo 6

对于你的第一个问题,是的.

对于你的第二个答案,我会给你一些我所遵循的提示.

  • 结合使用抽象类和接口来优化您的设计权衡.

使用抽象类

  • 在创建将广泛分发或重用的类库时 - 尤其是对客户端,使用优先于接口的抽象类; 因为,它简化了版本控制.

  • 使用抽象类为一系列类型定义公共基类.

  • 使用抽象类来提供默认行为.

  • 子类只是类逻辑上所属的层次结构中的基类.

使用界面

  • 在创建可以随意更改的独立项目时,请使用优先于抽象类的接口; 因为,它提供了更多的设计灵活性.

  • 使用接口来引入多态行为而无需子类化并模拟多重继承 - 允许特定类型支持多种行为.

  • 使用接口为值类型设计多态层次结构.

  • 真正意图使用不可变合同时使用接口.

  • 精心设计的界面定义了非常特定的功能范围.拆分包含不相关功能的接口.


Rem*_*anu 5

您可以实现任意数量的接口,但只能继承一个类.因此,C#中的类和接口是完全不同的野兽,你不能互换使用它们.在C#中,抽象类仍然是类,而不是接口.


Dan*_*ner 5

接口和抽象类服务于不同的目标。接口用于声明类的协定,而抽象类用于共享公共实现。

如果仅使用抽象类,则您的类不能从其他类继承,因为C#不支持多重继承。如果仅使用接口,则您的类不能共享通用代码。

public interface IFoo
{
    void Bar();
}

public abstract class FooBase : IFoo
{
    public abstract void Bar()
    {
        // Do some stuff usually required for IFoo.
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,我们可以在各种情况下使用该接口和基本实现。

public class FooOne : FooBase
{
    public override void Bar()
    {
        base.Bar(); // Use base implementation.

        // Do specialized stuff.
    }
}

public class FooTwo : FooBase
{
    public override void Bar()
    {
        // Do other specialized stuff.

        base.Bar(); // Use base implementation.

        // Do more specialized stuff.
    }
}

// This class cannot use the base implementation from FooBase because
// of inheriting from OtherClass but it can still implement IFoo.
public class FooThree : OtherClass, IFoo
{
    public virtual void Bar()
    {
        // Do stuff.
    }
}
Run Code Online (Sandbox Code Playgroud)