【问题标题】:Why do abstract classes need to define abstract methods from interfaces they implement?为什么抽象类需要从它们实现的接口中定义抽象方法?
【发布时间】:2014-03-18 18:36:08
【问题描述】:

当抽象类实现接口时,还需要定义或声明方法(如before 所问):

public interface MyInterface
{
  void Method();
}

public abstract class MyAbstractClass : MyInterface
{
  public abstract void Method(); // required, even though MyAbstractClass does not implement
}

public class MyClass : MyAbstractClass
{
  public override void Method()
  {
  }
}

public interface MyInterface2 : MyInterface
{
  // no need to declare Method() -- why can't abstract classes do the same for unimplemented methods?
}

c# 语言要求定义实现接口的抽象类的抽象方法的设计原理是什么?要求抽象类定义一个它没有实现的方法似乎是完全多余的(更糟糕的是,对于实际实现该方法的类必须将该方法标记为覆盖)。我看不出为什么抽象类不能像 MyInterface2 那样表现,它继承自 MyInterface 但不需要声明 MyInterface 的方法。

【问题讨论】:

  • 这就是接口的工作方式。它们保证方法存在,即使抽象类将其声明为抽象;这意味着继承该类的人必须实现该方法,这意味着该接口得到维护。编辑:这是我对其工作原理的微小理解。
  • 否则你会得到一个奇怪的层次结构,从你的抽象类派生的任何东西都需要记住它是从实现了所述接口的类派生的。
  • 如果您不希望抽象类具有接口方法,您可以将接口添加到具体类,而不是抽象类。
  • 感觉像是一个草率的心智模型
  • 我不明白为什么这个问题被标记为基于意见。 c# 语言设计者似乎对语言的设计相当理性,这个问题是询问特定要求的基本原理是什么。改写问题以强调这一点。

标签: c# interface abstract


【解决方案1】:

抽象类是一个成熟的类型,只是它不能被实例化。因此,即使它的某些方法没有实现,也必须声明它的 full 契约。特定抽象类的用户必须能够绑定到它的所有方法,无论它们来自接口还是直接在抽象类中声明。如果接口中的方法没有(至少)在抽象类中声明(如果甚至没有实现),则使用的方法无法绑定到它们。

此外,类和接口有些松散耦合。一个类可以声明一个方法,该方法稍后会映射到由其后代实现的接口中的相同签名方法。因此,从语言设计的角度来看,要求直接在抽象类上实现的所有接口方法都在其中实际声明,这又是一个“好主意”。

您可以将接口视为可分离的功能(使用显式实现时除外)。抽象类可以独立存在,它的直接用户不需要知道它的任何接口。

这是一个设计特性,只有虚方法可以不实现,因为在实践中需要利用虚方法的技术机制来实现抽象类的整个概念。


更新:示例:

public interface IFoo { void M(); }

public abstract class Bar : IFoo
{
    public virtual abstract void M();

    public void N() { }
}

public class Baz : Bar 
{
    public override void M() { … } 
}

… 

public void Method(Bar par)
{
    par.M();
}

…

Baz x = new Baz();
Method(x);

Method 将变量x 表示的实例视为Bar — 既不是Baz 也不是IFoo。换句话说,Bar 类的用户并不关心它是否实现了一个、两个、十个或根本没有接口。它所做的只是访问其成员。它依赖于Bar 的合同,不是IFoos 的合同。因此,如果Bar 实现IFoo,它必须定义来自IFoo 的所有成员。

【讨论】:

  • 我认为答案正朝着正确的方向发展,虽然我不明白为什么你说“抽象类是成熟的类型”,如果“它不能被实例化”。继承者接口的用户可以很好地绑定到它的方法,即使继承者接口没有定义被继承者的方法。
  • “完全成熟的类型”是指它的声明方面是完整的。它可以在允许类型的任何地方使用。唯一的例外是它不能在运行时实例化,因为它在 实现 方面是不完整的。抽象类的原因只是:允许不完整的实现,但需要完整的声明。
  • 那么抽象类可以用在哪里而不是接口呢?
  • 类是一个更丰富的概念。不管它们是否抽象。您的最后一个问题没有“微不足道”的答案。
  • 也许,当然,感谢您抽出宝贵时间回答,但这对我来说似乎仍然不满意。我希望约翰斯基特能加入!
【解决方案2】:

在实现接口的抽象类中创建的方法不需要是抽象的。抽象类也可以包含非抽象方法,您可以在那里定义接口的完整实现。继承类不需要重写任何这些方法。

另外,MSDN 中描述了抽象类:

抽象类必须为所有接口成员提供实现。

实现接口的抽象类可能将接口方法映射到抽象方法。

注意“可能”这个词,它不是“必须”。

还请注意MSDN 所说的关于实现接口的内容:

当类或结构实现接口时,该类或结构必须为接口定义的所有成员提供实现。

这适用于所有类型的类和结构。

【讨论】:

  • 很好的参考 MSDN;文档总是一个很好的起点。
  • 我认为 OP 关心的是为什么在抽象类中必须有接口方法的 any 声明,无论它本身是抽象的还是特定的。您的回答似乎在讨论其他问题。
  • @OndrejTucny 我只是在该主题上添加了一些更具体的内容。另外,我赞成您的回答,因为它也提供了很好的解释。
  • 我认为编辑后您的答案在技术上是完整的。另一方面,我的回答提供了一种元解释,从某种格式的角度来看,不需要完整性。我们应该把他们联合起来:-)
  • @OndrejTucny:正确 - 我关心的是为什么必须在抽象类中声明任何接口方法
【解决方案3】:

使用方法void Bar() 实现IFoo 的类可以选择是否希望公开公共方法Bar(),或者是否希望使用非公共成员来实现接口 [C#要求直接实现方法是公共的或私有的; vb.net 还允许protected 范围,这通常是抽象类最有用的排序]。

抽象类可以通过两种有用的方式实现IFoo.Bar():

public abtract void Bar();

// or

protected abstract void IFoo_Bar(); // Note that the exact name is arbitrary
void IFoo.Bar() { IFoo_Bar(); }

这两种实现都是合理的。第一个会做出不合理的假设,即一个类希望拥有一个在其代码中无处出现的公共方法;后者将要求编译器“猜测”应该给抽象方法起什么名字。因为没有明显优于任何替代的行为,C# 要求程序员指定所需的行为。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-15
    • 2018-07-19
    • 2011-12-23
    • 2020-04-03
    • 2015-08-19
    • 1970-01-01
    • 1970-01-01
    • 2011-02-11
    相关资源
    最近更新 更多