为什么抽象类需要从它们实现的接口定义抽象方法?

时间:2014-02-18 19:23:23

标签: c# interface abstract

当抽象类实现接口时,还需要定义或声明方法(如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的方法。

3 个答案:

答案 0 :(得分:6)

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

此外,这在MSDN中描述为抽象类:

  

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

     

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

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

请注意MSDN关于实现界面的内容:

  

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

对于各种类和结构都是如此。

答案 1 :(得分:6)

抽象类是一个完全成熟的类型,除了它无法实例化。因此,即使其某些方法未实现,也必须声明其完整合同。特定抽象类的用户必须能够绑定到其所有方法,无论是来自接口还是直接在抽象类中声明。接口中的方法没有(至少)在抽象类中声明(如果没有实现),则使用它们无法绑定它们。

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

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

这是一个设计特性,只有虚拟方法才能在没有实现的情况下离开,因为虚拟方法的技术机制需要利用抽象类的整个概念在实践中发挥作用。


更新:示例:

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的合同,不是IFoo合同。因此,如果Bar实施IFoo,则必须定义IFoo中的所有成员。

答案 2 :(得分:1)

使用方法IFoo实现void Bar()的类可以选择是否希望公开公共方法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#要求程序员指定所需的行为。