C# – 可以隐藏公开inheritance的方法(例如,派生类私有)

假设我拥有公共方法A和B的BaseClass,并通过inheritance创build了DerivedClass。

例如

public DerivedClass : BaseClass {} 

现在我想在DerivedClass中使用A和B开发一个方法C.有没有办法可以重写方法A和B在DerivedClass中是私有的,这样只有方法C才会暴露给想要使用我的DerivedClass的人?

这不可能,为什么?

在C#中,强迫你如果inheritance公共方法,你必须公开它。 否则,他们希望你不要从课堂中派生出来。

而不是使用is-a关系,你将不得不使用has-a关系。

语言devise者不允许这样做,以便更正确地使用inheritance。

例如,有人可能会不小心混淆了一个类Car从一个类Engine派生出来,以获得它的function。 但引擎是汽车使用的function。 所以你会想要使用has-a关系。 Car的用户不想访问Engine的界面。 而汽车本身不应该混淆引擎的方法与自己的方法。 也不是汽车的未来派生。

所以他们不允许它保护不良的inheritance层次结构。

你应该怎么做?

相反,你应该实现接口。 这使您可以使用has-a关系自由地使用function。

其他语言:

在C ++中,您只需在私有,公共或受保护的基类之前指定一个修饰符。 这使基础的所有成员公开到指定的访问级别。 在我看来,你不能在C#中做同样的事情。

重组的代码:

 interface I { void C(); } class BaseClass { public void A() { MessageBox.Show("A"); } public void B() { MessageBox.Show("B"); } } class Derived : I { public void C() { bA(); bB(); } private BaseClass b; } 

我明白上面的类的名字有点渺茫:)

其他build议:

其他人则build议将A()和B()公开并抛出exception。 但是这并不能为人们提供一个友善的课堂,而且也没有什么意义。

例如,当您尝试从List<object>inheritance,并且想要隐藏直接的Add(object _ob)成员时:

 // the only way to hide [Obsolete("This is not supported in this class.", true)] public new void Add(object _ob) { throw NotImplementedException("Don't use!!"); } 

这不是最好的解决scheme,但它是做的。 智能感知仍然接受,但在编译时你会得到一个错误:

错误CS0619:'TestConsole.TestClass.Add(TestConsole.TestObject)'已过时:'这个类不支持'。

这听起来像个坏主意。 Liskov不会留下深刻的印象。

如果您不希望DerivedClass的使用者能够访问DeriveClass.A()和DerivedClass.B()方法,那么我build议DerivedClass应该实现一些公共接口IWhateverMethodCIsAbout,DerivedClass的使用者实际上应该与IWhateverMethodCIsAbout交谈并知道根本就没有关于BaseClass或DerivedClass的实现。

你需要的是组成不是inheritance。

 class Plane { public Fly() { .. } public string GetPilot() {...} } 

现在,如果你需要一种特殊的平面,比如有一个PairOfWings = 2的平面,但是除此之外,一个平面都可以。你inheritance了平面。 通过这个,你可以声明你的派生符合基类的合约,并且可以被替代而不会在任何基类的地方闪烁。 例如LogFlight(平面)将继续使用BiPlane实例。

但是,如果您只需要您想要创build的新Bird的Fly行为,而不愿意支持完整的基类合同,则可以编写。 在这种情况下,重构方法的行为重用到一个新的types的飞行。 现在在Plane和Bird中创build并保存对这个类的引用。 您不会inheritance,因为Bird不支持完整的基类合同…(例如,它不能提供GetPilot())。

基于同样的原因, 当你重写的时候你不能减less基类方法的可见性。你可以重写并在派生中公开基类私有方法,反之亦然。 例如,在这个例子中,如果我派生了一个平面“BadPlane”,然后覆盖和“隐藏”GetPilot() – 使它私有; 一个客户端方法LogFlight(平面p)将适用于大多数平面,但如果LogFlight的实现碰巧需要/调用GetPilot(),将炸毁“BadPlane”。 由于基类的所有派生都被期望在任何基类参数所在的地方都是“可替代的”,所以这是不允许的。

我所知道的唯一方法就是使用Has-A关系,只实现你想暴露的函数。

隐藏是一个非常滑的斜坡。 IMO的主要问题是:

  • 它依赖于实例的devise时声明types,这意味着如果您执行类似于BaseClass obj = new SubClass()的操作,则调用obj.A(),隐藏将被击败。 BaseClass.A()将被执行。

  • 隐藏可以很容易地掩盖基本types中的行为(或行为变化)。 当你拥有等式的双方时,或者如果调用“base.xxx”是你的子成员的一部分,这显然不是一个问题。

  • 如果你真的拥有基础/子类方程的双方,那么你应该能够devise一个比制度化的隐藏/阴影更易于pipe理的解决scheme。

我会说,如果你有一个代码库,你想这样做,这不是最好的devise的代码库。 这通常是一个阶层的标志,需要一定的公共签名,而另一个派生的阶级不需要它。

即将出现的编码范式被称为“构成超越inheritance”。 这直接背离了面向对象开发的原则(特别是单一责任原则和开放/封闭原则)。

不幸的是,我们很多开发人员被教导面向对象的方式,我们已经形成了立即思考inheritance而不是构图的习惯。 我们倾向于有更大的class级,因为他们可能被包含在同一个“真实世界”对象中,所以他们有许多不同的责任。 这可能会导致5级以上的类层次结构。

开发人员在处理inheritance时通常不会考虑的一个不幸的副作用是,inheritance是您可以在代码中引入的最强烈的依赖关系之一。 您的派生类现在强烈依赖于它inheritance的类。 这会使你的代码长期变得脆弱,导致混淆的问题,即在基类中改变特定的行为以不明确的方式破坏派生类。

打破你的代码的一种方法是通过另一个答案中提到的接口。 无论如何,这是一个聪明的事情,因为你希望类的外部依赖绑定到抽象,而不是具体/派生types。 这使您可以在不更改接口的情况下更改实现,而不会影响相关类中的一行代码。

我宁愿维护一个拥有数百/数千个甚至更多类的小系统,而不是处理一个大量使用多态/inheritance的系统,而更less的类更加紧密耦合。

也许在面向对象开发方面最好的资源是Robert C. Martin的书, 敏捷软件开发,原则,模式和实践 。

@Brian R. Bondy向我指出了一篇关于通过inheritance和关键字隐藏的有趣文章。

http://msdn.microsoft.com/en-us/library/aa691135(VS.71).aspx

所以作为解决方法,我会build议:

 class BaseClass { public void A() { Console.WriteLine("BaseClass.A"); } public void B() { Console.WriteLine("BaseClass.B"); } } class DerivedClass : BaseClass { new public void A() { throw new NotSupportedException(); } new public void B() { throw new NotSupportedException(); } public void C() { base.A(); base.B(); } } 

这样这样的代码会抛出一个NotSupportedException

  DerivedClass d = new DerivedClass(); dA(); 

如果它们是在原始类中公开定义的,则不能在派生类中将其重写为私有的。 但是,您可以使公共方法抛出exception并实现您自己的私有函数。

编辑:豪尔赫·费雷拉是正确的。

Interesting Posts