当前位置:  开发笔记 > 编程语言 > 正文

C# - 可以隐藏公开继承的方法(例如,对派生类进行私有)

如何解决《C#-可以隐藏公开继承的方法(例如,对派生类进行私有)》经验,为你挑选了4个好方法。

假设我有公共方法A和B的BaseClass,我通过继承创建DerivedClass.

例如

public DerivedClass : BaseClass {}

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



1> Brian R. Bon..:

这不可能,为什么?

在C#中,强制要求你如果继承了公共方法,就必须将它们公之于众.否则他们希望你不要从这个阶段派生出来.

您不必使用is-a关系,而是必须使用has-a关系.

语言设计者不会故意允许这样做,以便您更正确地使用继承.

例如,有人可能会意外地将类Car混淆为从类Engine派生以获得它的功能.但引擎是汽车使用的功能.所以你想要使用has-a关系.Car的用户不希望访问Engine的界面.汽车本身不应该将引擎的方法与它自己的方法混淆.Nor Car的未来派生.

所以他们不允许它保护你免受糟糕的继承层次结构的影响.

你应该怎么做?

相反,你应该实现接口.这使您可以使用has-a关系自由使用功能.

其他语言:

在C++中,您只需在private,public或protected的基类之前指定一个修饰符.这使得基础的所有成员都公开到指定的访问级别.对我来说,你不能在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()
    {
        b.A();
        b.B();
    }

    private BaseClass b;
}

我理解上面这些类的名字有点没有实际意义:)

其他建议:

其他人建议将A()和B()公开并抛出异常.但是,这并没有为人们提供友好的课程,而且实际上没有意义.


不幸的是,无法做到这一点意味着当你使用其他人设计糟糕的库时,不可能将你的代码库与它隔离开来.一个很好的例子是System.Web中的WebControl类---它有大量滥用内联样式的公共属性,并且因为它们将所有内容都卷入基类,所以没有办法创建一个继承它的CleanWebControl类并隐藏它糟糕的设计.如果可能的话,隐藏别人的糟糕设计会很有用,特别是当.NET Framework本身的设计不好时.
nono有一个很好的答案,使用Obsolete属性.

2> 小智..:

例如,当您尝试从a继承时List,您想要隐藏直接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!!");
}

这不是最理想的解决方案,但它可以完成这项工作.Intellisense仍然接受,但在编译时你会收到一个错误:

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


美丽!这就是我所需要的。我有一个结构不好的坏类,我无法更改(别人拥有)拥有需要隐藏的成员的类。这很好。请注意,C ++允许您执行此操作。

3> Hamish Smith..:

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

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



4> Gishu..:

你需要的是组合而不是继承.

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

现在,如果您需要一种特殊的平面,例如具有PairOfWings = 2的平面,但平面可以做任何事情.您继承平面.通过这种方式,您声明您的派生符合基类的契约,并且可以替换而不会在期望基类的任何地方闪烁.例如,LogFlight(Plane)将继续使用BiPlane实例.

但是,如果您只需要想要创建的新Bird的Fly行为,并且不愿意支持完整的基类合约,那么您需要编写.在这种情况下,重构方法的行为以重用到新类型的Flight中.现在在Plane和Bird中创建并保持对此类的引用.你没有继承,因为Bird不支持完整的基类契约......(例如它不能提供GetPilot()).

出于同样的原因,您在覆盖时无法降低基类方法的可见性.您可以在派生中覆盖并使基本私有方法公开,但反之亦然.例如,在这个例子中,如果我派生出一种Plane"BadPlane",然后覆盖并"隐藏"GetPilot() - 将其设为私有; 一个客户端方法LogFlight(Plane p)适用于大多数Planes,但如果LogFlight的实现恰好需要/调用GetPilot(),它将会爆炸为"BadPlane".由于预期基类的所有派生都是"可替代的",无论何时需要基类参数,都必须禁止这种派生.

推荐阅读
拾味湖
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有