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并实现您自己的私有函数。
编辑:豪尔赫·费雷拉是正确的。