假设我有BaseClass与公共方法A和B、我建立的基类实现通过继承。

例如

public DerivedClass : BaseClass {}

现在我想要开发一种方法C中的基类实现一个使用和B。有没有一种方式我可以替代方法A和B可以在私人基类实现这样,唯一的方法C是暴露一个人想要利用我的的基类实现?

有帮助吗?

解决方案

这不可能,为什么?

在C#中,强制要求你继承公共方法,你必须公开它们。否则他们希望你不要从这个阶段派生出来。

您必须使用has-a关系,而不是使用is-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()公开并抛出异常。但是,这并没有为人们提供友好的课程,而且实际上没有意义。

其他提示

例如,当您尝试从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!!");
}

这不是最理想的解决方案,但它可以胜任。 Intellisense仍然接受,但在编译时会出现错误:

  

错误CS0619:'TestConsole.TestClass.Add(TestConsole.TestObject)'已废弃:'此类不支持此。'

这听起来不错。 Liskov 不会留下深刻印象。

如果你不希望DerivedClass的使用者能够访问方法DeriveClass.A()和DerivedClass.B()我会建议DerivedClass应该实现一些公共接口IWhateverMethodCIsAbout并且DerivedClass的消费者实际上应该与之交谈IWhateverMethodCIsAbout并且对BaseClass或DerivedClass的实现一无所知。

您需要的是合成而非继承。

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但会爆炸<!>“BadPlane <!>”;如果LogFlight的实现恰好需要/调用GetPilot()。 由于预期基类的所有派生都是“可替代的”,因此必须禁止这样做。

我所知道的唯一方法是使用Has-A关系并仅实现您想要公开的函数。

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

http://msdn.microsoft.com/ EN-US /库/ 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();

隐藏的是一个非常滑坡。主要的问题,海事组织是:

  • 它依赖的设计时 《宣言》类型的实例, 这意味着如果你不喜欢的东西 BaseClass obj=new类(),然后 呼叫obj。一个(),隐藏被击败。BaseClass.一个()将被执行。

  • 躲在可以很容易模糊 行为(或行为变化)在 基类型。这显然是 少的关切,当你自己的两个 双方式,或者如果打电话的基础。xxx'是部分的子部件。

  • 如果你真的 自己的两侧的基地/子类的公式,然后你应该能够制定一个更易于管理解决方案制度化躲/阴影。

我想说如果你有一个你想要这样做的代码库,它就不是设计最好的代码库。它通常是需要某个公共签名的层次结构中的一个类的标志,而从该类派生的另一个类不需要它。

即将推出的编码范例称为<!>“;基于继承的组合。<!>”;这直接取决于面向对象开发的原则(特别是单一责任原则和开放/封闭原则)。

不幸的是,我们很多开发人员被教导面向对象的方式,我们已经养成了立即考虑继承而不是组合的习惯。我们倾向于拥有更大的类,这些类具有许多不同的职责,仅仅因为它们可能包含在相同的<!>“真实世界<!>”中。宾语。这可能导致深层次超过5级的类层次结构。

开发人员在处理继承时通常不会考虑的一个令人遗憾的副作用是,继承是您可以引入代码的最强依赖形式之一。您的派生类现在强烈依赖于它继承的类。这可能会使您的代码在长期内更加脆弱,并导致混淆问题,即更改基类中的某个行为会以不明显的方式破坏派生类。

破解代码的一种方法是通过另一个答案中提到的接口。这是一件很聪明的事情,因为你希望类的外部依赖项绑定到抽象,而不是具体/派生类型。这允许您在不更改接口的情况下更改实现,所有这些都不会影响依赖类中的一行代码。

我宁愿维护一个拥有数百/数千甚至更多类的系统,这些系统都是小型且松散耦合的,而不是处理大量使用多态/继承的系统,并且具有更少紧密耦合的类。

面向对象开发的最佳资源可能是Robert C. Martin的书,敏捷软件开发,原则,模式和实践

如果它们在原始类中被公开定义,则不能将它们覆盖为派生类中的私有。但是,您可以使public方法抛出异常并实现您自己的私有函数。

编辑:Jorge Ferreira是对的。

虽然这个问题的答案是<!>“no <!>”,但我想指出其他人来到这里(因为OP有点暗示第三方的装配访问) )。当其他人引用一个程序集时,Visual Studio应该遵循以下属性,因此它不会显示在intellisense中(隐藏,但仍然可以调用,所以要小心):

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

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

另一个技巧取决于NOT尽可能从基类继承,其中base具有相应的接口(例如IList<T> for List<T>)。实现接口<!>显式<!>;还会在类类型上隐藏intellisense中的那些方法。例如:

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

如果是var obj = new GoodForNothing()Dispose()方法将无法在obj上使用。但是,对于明确键入IDisposable to <=>的任何人都可以使用它。

此外,您还可以包装基类型而不是继承它,然后隐藏一些方法:

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...*/
}
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top