一个类是否有办法“删除”它继承的方法?

33

一个类是否有办法“删除”它继承的方法?

例如,如果我不希望我的类有一个ToString()方法,我能否做某些事情使其不再可用?


2
http://www.codinghorror.com/blog/2004/08/inherits-nothing.html - Svisstack
1
这被称为“拒绝遗赠”代码异味:“一个类以一种使得派生类不遵守基类契约的方式覆盖了基类的方法”。http://en.wikipedia.org/wiki/Code_smell - Mathias
没有办法删除一个方法。如果这个方法是virtual(标记为virtualabstractoverride),你很幸运,因为基类的作者允许你决定这个方法的行为。你可以让它什么也不做,或者抛出一个异常(但请注意,这可能会打破基类对你的方法的期望,所以在某些情况下会引入问题)。如果这个方法不是虚方法,你无能为力。用另一个方法来隐藏它是一个非常糟糕的想法(当然也不能删除它)。 - Jeppe Stig Nielsen
4个回答

36
不行——这将违反里氏替换原则。你应该始终能够像使用超类型的实例一样使用子类型的实例。
不要忘记,调用者可能只知道您的类型是基础类型或接口。考虑以下代码:
object foo = new TypeWithToStringRemoved();
foo.ToString();

希望它能编译,不是吗?那么在执行时你会期望发生什么?

对于ToString、GetHashCode、Equals和GetType,没有办法避免它们出现 - 但通常,如果有一些方法你想要从一个基类型中“删除”,那就意味着你本来就不应该从它继承。个人认为,在面向对象编程中,继承的作用有些被夸大:当它有用时它确实非常有用,但通常我更喜欢组合而非继承,并且使用接口作为抽象的形式,而不是基类。


1
你是完全正确的 - 让 ToString() 方法抛出异常尤其危险。有很多比你展示的(直接调用)更为隐藏ToString() 使用方法。 - tanascius
但是你肯定可以使用new修饰符来隐藏一个继承的成员(并抛出一个NotSupportedException,就像tanascius建议的那样),而不会违反任何原则或引发意外异常。 - Allon Guralnek
这个答案是正确的,但有时我只想窃取别人类的实现,但只导出一个有限的接口。为此,我必须显式地代理我想要的每个方法。 - Adrian Ratnapala
@AdrianRatnapala:是的,这有点痛苦 - 但这并不意味着滥用继承(并公开您不想公开的方法)是更好的方法。如果C#和Java对混入有更好的支持,那就太好了。 - Jon Skeet
是的。我喜欢Go语言的匿名嵌入。但是虽然我希望其他编程语言也有这个特性,但我怀疑它会与现有的特性(如继承)重叠太多。 - Adrian Ratnapala
显示剩余5条评论

22

您可以抛出NotSupportedException,将其标记为Obsolete并使用EditorBrowsable

[EditorBrowsable( EditorBrowsableState.Never )]
[Obsolete( "...", false )]
void YourMethod()
{
    throw new NotSupportedException( "..." );
}

编辑:
正如其他人指出的那样:我描述了一种“禁用”方法的方法,但您必须仔细考虑您想在哪里使用它。特别是抛出异常可能是非常危险的事情。


@tanascius:如果你从废弃的属性中得到异常参数,那么你的代码就很好了;-) - Svisstack
@Svisstack:不,那是两个不同的字符串^^也许它们应该不同,因为过时消息是给开发人员的,而异常消息可能会传达给用户?嗯,可能不应该这样 - 至少不应该这样。 - tanascius
3
如果你真的想要禁用这个方法,使用[Obsolete("...", true)]会更好吧?这样调用这个方法就会产生编译错误,不需要抛出异常。 - piedar
1
请查看ObsoleteAttributeIsError属性。如果IsErrortrue,编译器将生成一个错误;如果为false,则会生成一个警告。 - DavidRR

7

正如其他人指出的那样,您无法“删除”一个方法,但如果您觉得它在某些方面对您造成了不利影响,您可以在派生类中隐藏它。

根据微软的文档(现已停用):

class Base
{
   public static void F() {}
}
class Derived: Base
{
   new private static void F() {}   // Hides Base.F in Derived only
}
class MoreDerived: Derived
{
   static void G() { F(); }         // Invokes Base.F
}

F必须受到保护,不是吗? - Christophe Debove
@ChristopheDebove 那个例子直接来自 MSDN,所以我认为他们的意思是让它保持私有。 - Roman

1

简短回答,不行,因为所有类都继承自object类,而object类有这个方法。


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