C# - 可以公开继承的方法隐藏(例如,由私有的派生类)(C# - Can publicly inh

2019-06-24 13:30发布

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

public DerivedClass : BaseClass {}

现在我想开发一个DerivedClass方法C中使用A和B.有没有办法我可以重写方法A和B是私有的DerivedClass因此只有方法c中暴露的人谁愿意用我的DerivedClass?

Answer 1:

这是不可能的,为什么呢?

在C#中,它是强加给你,如果你继承的公共方法,你必须让他们公开。 否则,他们希望你不要从类摆在首位获得。

除了使用IS-有关系的,你就必须使用具有-的关系。

让您使用继承更恰当的语言的设计者不允许故意的。

例如,一个可能会意外地混淆一个类从汽车类发动机派生得到它的功能。 但是,一个引擎是使用汽车的功能。 所以,你会希望使用具有-的关系。 汽车的用户不希望访问该引擎的接口。 与汽车本身不应混淆引擎与它自己的方法。 也不汽车的未来推导。

因此,他们不容许它保护你从坏的继承层次。

你应该怎么做呢?

相反,你应该实现的接口。 这使你可以自由地使用具有-关系具有的功能。

其他语言:

在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()
    {
        b.A();
        b.B();
    }

    private BaseClass b;
}

我明白上面类的名称有点实际意义:)

其他建议:

也有人建议,使A()和B()公共和抛出异常。 但是,这并不让人们使用它并没有真正意义友好类。



Answer 2:

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

这不是真的是最可取的解决方案,但它的工作。 智能感知仍然接受,但是在编译时出现错误:

错误CS0619:“TestConsole.TestClass.Add(TestConsole.TestObject)”已过时:“这是不是在这个类的支持。”



Answer 3:

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

如果你不想DerivedClass的消费者能够访问方法DeriveClass.A()和DerivedClass.B()我建议DerivedClass应该实现一些公共接口IWhateverMethodCIsAbout和DerivedClass的消费者实际上应该是交谈IWhateverMethodCIsAbout,知道一无所知的BaseClass或DerivedClass在所有实施。



Answer 4:

你需要的是组成不继承。

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

现在,如果你需要一种特殊的飞机,比如一个有PairOfWings = 2否则做每件事飞机可以..你继承平面。 通过这个声明,您的推导符合基类的合同,可以不眨眼的地方一个基类有望取代。 如LogFlight(平面)将继续与双翼飞机的实例工作。

但是如果你只需要飞行为要创建并不愿意支持完整的基础类合同一个新的鸟,你撰写代替。 在这种情况下,重构的方法的行为重用到一个新的类型的飞行。 现在创建并保持在两个平面和伯德这一类的引用。 你不继承,因为鸟不支持完整的基础类合同......(例如,它不能提供GetPilot())。

出于同样的原因, 当你重写你不能减少的基类方法的可见性..你可以重写,并在推导基地私有方法公开,但反之则不行。 例如,在这个例子中,如果我得到一个类型的飞机“BadPlane”的,然后覆盖和“隐藏” GetPilot() - 使私有的; 客户端方法LogFlight(平面P)将用于大多数飞机的工作,但将爆破“BadPlane”如果LogFlight的执行情况需要/调用GetPilot()。 由于基类的所有派生预计将“替代”无论一个基类参数是预期的,这必须被禁止。



Answer 5:

只有这样,才能做到这一点,我知道的是使用具有-A的关系,只实现要公开的功能。



Answer 6:

@布赖恩河邦迪向我指出一个有趣的文章,通过继承和新的关键字隐藏。

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

因此,作为解决办法,我建议:

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();
    d.A();


Answer 7:

隐藏是一个相当大滑坡。 的主要问题,IMO,主要有:

  • 这取决于设计时声明类型的实例,obj.A(),这意味着,如果你这样做的BaseClass的obj =新的子类(),然后调用,藏匿被击败。 BaseClass.A()将被执行。

  • 在基本类型隐藏可以非常容易地晦涩行为(或行为的变化)。 这显然是不太关心的时候你自己的等式的两边,或者叫“base.xxx”是你的子件的主要部分。

  • 如果你真的自己底座/次一级方程式的两边,那么你应该能够设计出比制度化隐藏/遮蔽一个更易于管理的解决方案。


Answer 8:

我要说的是,如果你有,你是想用做这个代码库,它是不是最好的设计代码库。 这是典型的层次结构的一个级别需要一定的公共签名,同时从该类派生的其他类并不需要它一类的标志。

即将到来的编码范例被称为“组成了传承。” 这直接播放过的面向对象的开发(特别是单一职责原则和开/关原则)的原则。

不幸的是,很多开发商我们被教导面向对象的方式,我们已经形成的立即想着继承,而不是组成一个习惯。 我们往往有有许多不同的责任,只是因为他们可能包含有相同的“真实世界”对象大类别。 这可能会导致类层次结构是5+级深。

一个不幸的副作用,开发商通常不想想有继承打交道时是遗传形成的,你都不能引入你的代码中最强形式的一个依赖。 你的派生类是现在强烈地依赖于它是从继承的类。 这可以使你的代码从长远来看,更脆,并导致混淆的问题,其中改变在晦涩的方式派生类的基类减免一定的行为。

打破你的代码的一个方法是通过接口置身于另一个答复中提到。 这是反正做聪明的事情,只要你想一类的外部依赖绑定到抽象,没有具体的/派生类型。 这允许您更改执行不改变接口,都没有影响一行代码在你的依赖类。

我宁愿不是保持与数百/千/更类,都是小和松耦合的系统,比对付一个系统,使大量使用多态/继承的,并具有更紧密耦合的较少类。

也许最好的资源在那里对面向对象的开发是罗伯特·C·马丁的书, 敏捷软件开发,原则,模式和实践 。



Answer 9:

如果他们在原来的类中定义的公开,不能覆盖他们在你的派生类的私人。 但是,你可以让公众方法抛出一个异常,并实现自己的私有函数。

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



Answer 10:

而问题的答案是“不”,有一个提示,我想指出别人这里到达(考虑到OP是那种由第三方暗指装配访问)。 当别人引用的组件时,Visual Studio应履行下列属性,所以它不会显示在IntelliSense(隐藏,但仍然可以调用,所以要小心):

[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]

如果你没有其他选择,你应该能够使用new的隐藏基本类型方法的方法,返回=> throw new NotSupportedException(); ,并与上面的属性结合起来。

另一特技取决于从基类,如果可能的,其中所述基座具有相应的接口(如NOT继承IList<T>List<T> 实现接口的“明确”也将隐藏从智能感知的类类型的方法。 例如:

public class GoodForNothing: IDisposable
{
    void IDisposable.Dispose() { ... }
}

在的情况下, var obj = new GoodForNothing()所述Dispose()方法将不提供关于obj 。 然而,这将是提供给任何人谁明确地类型强制转换objIDisposable

此外,你也可以换一个基类,而不是从它继承,然后隐藏一些方法:

public class MyList<T> : IList<T>
{
    List<T> _Items = new List<T>();
    public T this[int index] => _Items[index];
    public int Count => _Items.Count;
    public void Add(T item) => _Items.Add(item);
    [System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
    void ICollection<T>.Clear() => throw new InvalidOperationException("No you may not!"); // (hidden)
    /*...etc...*/
}


文章来源: C# - Can publicly inherited methods be hidden (e.g. made private to derived class)
标签: c# class derived