C#: 抽象类需要实现接口吗?

160

我的C#测试代码:

namespace DSnA
{
    public abstract class Test : IComparable
    {

    }
}

导致以下编译器错误的结果:

error CS0535: 'DSnA.Test' does not implement interface member
'System.IComparable.CompareTo(object)'

由于类Test是一个抽象类,为什么编译器要求它实现接口?这个要求不应该只针对具体类吗?


哈哈,我写了一件事情,然后决定改变它。抱歉。 :) - Joel
6
根据被接受答案的负投票和评论,我认为这些负投票是因为问题的措辞方式。OP提问“为什么是这样”,这已经超出了stackoverflow的范围。作为自己也遇到过这种情况的人,这个问题更像是“我有什么遗漏吗?我真的必须提供实现吗?那不是违背抽象类的目的吗?”对此回答是,“不,你不必提供实现(这会违反抽象类的目的),但是这里是你需要做的事情,让你的情况可以工作。” - ToolmakerSteve
我发现了一种情况,你必须提供一个实现。这是当接口有一个可选参数时。如果你在基类中将该方法声明为抽象的,那么继承该类的子类将无法在没有可选参数的情况下编译(这就失去了可选参数的目的)。在这种情况下,我只会抛出NotImplementedException异常。 - Paul McCarthy
请忽略我的先前评论 - 它没有像预期的那样工作,最少惊奇原则在这里并不适用。 - Paul McCarthy
3个回答

191

在C#中,实现接口的类必须定义该接口的所有成员。对于抽象类,您只需使用abstract关键字定义这些成员:

interface IFoo
{
    void Bar();
}

abstract class Foo : IFoo
{
    public abstract void Bar();
}
换句话说,你不必对抽象类进行“实现”(这会对抽象类造成可怕的限制);然而,在C#中,你需要明确告诉编译器你故意将责任传递给具体的子类,上述代码行展示了如何做到这一点。注释和负评认为这不是问题的答案,缺失了重点。当有人在Stack Overflow上收到此编译错误消息,并且拥有一个不适合提供实现的抽象类时,他们就没有好的解决方案 - 除非他们拥有上述信息,否则只能编写抛出运行时异常的实现方法,这是一个可怕的解决办法。无论C#是否需要这种明确性都超出了Stack Overflow的范围,也与问题及其答案无关。

2
@Ben 刚看到你的评论。你可能已经解决了,但如果有其他人需要,可以查看显式接口实现:http://msdn.microsoft.com/en-us/library/ms173157.aspx - Joel
2
@Joel @Ben 我认为显式接口不能与抽象类一起使用。在上面的示例代码中,将Foo中的定义更改为public abstract void IFoo.Bar();,你会收到“public”和“abstract”不是有效修饰符的投诉。 - Darren Cook
12
考虑到这是一个抽象类,编译器应该知道如何填充空白处,因此这并没有回答为什么这样做是必要的。在Java中,这是不必要的,这使得一些有用的模式成为可能,例如在IoC容器(例如Spring/JavaEE)上使用装饰器模式(当需要装饰受管理接口的特定方法时)。但是,在.net中进行相同的实现将不得不迫使开发人员变得非常冗长,尤其是对于像nhibernate的ISession这样的大型接口。 - Sheepy
1
AspectJ的混入是另一个例子。它允许您将多个抽象类的部分实现混合到单个接口中。每个抽象类只需要实现它想要实现的方法。没有愚蠢的抽象方法样板文件会妨碍您,如果我要在.NET中重新创建相同的功能。 - Sheepy
1
@Sheepy - 确实,但是,在我看来,您误解了提问者需要什么以及这确实是一个“答案”的方式。我也有同样的问题-因为要求提供实现并没有意义,所以我被卡住了。答案是:您不必“实现”它-但是这里是您需要做的事情,告诉编译器您不打算实现它。(您[正确地]说这不是一个回答的问题,将不是一个适当的stackoverflow问题-它只会被关闭为离题。) - ToolmakerSteve
显示剩余2条评论

15

1
非常清晰的答案,很棒你提供了两种情况,因为有时候你可能也想在基类中实现这种行为。 - VinKel
这里出现的一个问题是:为什么这些C#样板声明(显然它们是)需要存在于抽象类中,而抽象类本来可以更简洁和更短(从而混淆类)?在我的C#项目中,我有很多抽象类和接口 - 我大部分时间所做的就是在Visual Studio中复制和粘贴方法声明。 - forsberg

7

他们不必实际实现接口。接口方法/属性可以是抽象的甚至是虚拟的,因此由子类来实际实现它们。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接