C # - Können öffentlich geerbten Methoden versteckt werden (zum Beispiel als privat zu abgeleiteten Klasse)

StackOverflow https://stackoverflow.com/questions/106383

  •  01-07-2019
  •  | 
  •  

Frage

Angenommen, ich habe mit öffentlichen Baseclass Methoden A und B, und ich schaffe DerivedClass durch Vererbung.

z.

public DerivedClass : BaseClass {}

Jetzt mag ich eine Methode C in DerivedClass entwickeln, die A verwendet und B. Gibt es eine Möglichkeit, Methoden A und B außer Kraft setzen kann in DerivedClass privat zu sein, so dass nur Verfahren C jemandem ausgesetzt ist, der will meinen DerivedClass verwenden ?

War es hilfreich?

Lösung

Es ist nicht möglich, warum?

In C # wird auf Sie gezwungen, wenn man öffentliche Methoden erben, müssen Sie sie öffentlich machen. Andernfalls sie erwarten, dass Sie nicht aus der Klasse in erster Linie abzuleiten.

Anstelle der ist-eine Beziehung, würden Sie die hat-eine Beziehung verwenden.

Die Sprachdesigner dies nicht absichtlich ermöglichen, so dass Sie die Vererbung mehr richtig zu verwenden.

Zum Beispiel könnte man versehentlich eine Klasse Auto verwechselt aus einer Klasse Motor abzuleiten es Funktionalität zu erhalten. Aber ein Motor ist Funktionalität, die mit dem Auto verwendet wird. So möchte man die hat-eine Beziehung verwenden. Der Benutzer des Autos will keinen Zugriff auf die Schnittstelle zum Motor haben. Und das Auto selbst soll den Motor Methoden nicht zu verwechseln mit einem eigenen. Auch Auto-Zukunft Ableitungen.

So sie lassen Sie es nicht Sie von schlechten Vererbungshierarchien zu schützen.

Was sollten Sie tun, stattdessen?

Stattdessen sollten Sie Schnittstellen implementieren. Dies lässt Sie frei, die hat-eine Beziehung haben Funktionalität verwendet wird.

Weitere Sprachen:

In C ++ Sie einfach einen Modifikator vor der Basisklasse von privaten angeben, öffentlich oder geschützt. Das macht alle Mitglieder der Basis, die zu dieser bestimmten Zugriffsebene öffentlich waren. Es scheint dumm zu mir, dass Sie das gleiche in C # nicht tun können.

Der neu strukturierte Code:

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;
}

Ich verstehe die Namen der oben genannten Klassen sind ein wenig strittig:)

Andere Vorschläge:

Andere haben vorgeschlagen, Ausnahmen A () und B () öffentlich zu machen und werfen. Aber das macht nicht eine freundliche Klasse für Menschen zu verwenden und es nicht wirklich Sinn machen.

Andere Tipps

Wenn Sie zum Beispiel versuchen, von einem List<object> zu erben, und Sie mögen das direkte Add(object _ob) Mitglied verbergen:

// 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!!");
}

Es ist nicht wirklich die am meisten bevorzugte Lösung, aber es macht den Job. Intellisense noch akzeptiert, aber bei der Kompilierung erhalten Sie eine Fehlermeldung:

  

Fehler CS0619: 'TestConsole.TestClass.Add (TestConsole.TestObject)' ist veraltet: 'Dies ist nicht in dieser Klasse unterstützt wird'

Das klingt wie eine schlechte Idee. Liskov nicht beeindrucken.

Wenn Sie nicht möchten, dass die Verbraucher von DerivedClass der Lage sein, Zugriffsmethoden DeriveClass.A () und DerivedClass.B () Ich würde vorschlagen, dass DerivedClass eine öffentliche Schnittstelle IWhateverMethodCIsAbout und die Verbraucher von DerivedClass implementieren sollten sollte eigentlich zu reden IWhateverMethodCIsAbout und weiß nichts über die Durchführung von Baseclass oder DerivedClass überhaupt.

Was Sie brauchen, ist Zusammensetzung nicht Vererbung.

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

Nun, wenn Sie eine besondere Art von Flugzeug benötigen, wie zum Beispiel eines, die PairOfWings = 2, aber sonst tut alles, was ein Flugzeug kann hat .. Sie erben Ebene. Damit erklären Sie, dass Ihre Ableitung den Vertrag der Basisklasse erfüllt und kann ohne blinken ersetzt werden überall dort, wo eine Basisklasse erwartet wird. z.B. LogFlight (Ebene) weiterhin mit einer Doppeldeckers Instanz arbeiten.

Wenn Sie jedoch nur das Fliegenverhalten für einen neuen Vogel müssen Sie erstellen möchten, und sind nicht bereit, die komplette Basisklasse Vertrag zu unterstützen, komponieren Sie stattdessen. In diesem Fall Refactoring das Verhalten der Methoden in einen neuen Typ Flight wiederzuverwenden. Nun Verweise auf diese Klasse in den beiden Flugzeug und Vogel schaffen und halten. Sie erben nicht, weil der Vogel nicht die komplette Basisklasse Vertrag unterstützen ... (zum Beispiel kann es nicht GetPilot liefern ()).

Aus dem gleichen Grunde, Sie können die Sichtbarkeit der Basisklasse Methoden reduzieren, wenn Sie außer Kraft setzen .. Sie können eine Basis private Methode Öffentlichkeit bei der Ableitung außer Kraft setzen und, aber nicht umgekehrt. z.B. In diesem Beispiel, wenn ich eine Art Plane „BadPlane“ ableiten und dann außer Kraft setzen und „Hide“ GetPilot () - macht es privat; eine Client-Methode LogFlight (Ebene P) wird für die meisten Flugzeuge funktionieren, aber für „BadPlane“ sprengen, wenn die Durchführung von LogFlight geschieht GetPilot müssen / () aufrufen. Da alle Ableitungen von einer Basisklasse erwartet ‚ersetzbar‘ zu sein, wo eine Basisklasse param erwartet wird, hat dies nicht zugelassen werden.

Der einzige Weg, dies zu tun, die ich kenne ist ein Ein Has-Beziehung zu verwenden und nur implementieren die Funktionen, die Sie machen möchten.

@ Brian R. Bondy wies mich auf einen interessanten Artikel über Hiding durch Vererbung und das neue Stichwort.

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

Um Abhilfe würde ich vorschlagen:

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();
    }
}

Auf diese Weise Code wie dies wirft ein NotSupportedException :

    DerivedClass d = new DerivedClass();
    d.A();

Verstecken ist ein ziemlich schlüpfrigen Abhang. Die wichtigsten Themen, IMO, sind:

  • Es ist abhängig von der Design-Zeit Deklaration Typ der Instanz, das heißt, wenn Sie etwas tun, wie Baseclass obj = new SubClass (), dann rufen obj.A () versteckt besiegt. BaseClass.A () ausgeführt wird.

  • Verstecken kann sehr leicht obskuren Verhalten (oder Verhaltensänderungen) in der Basistyp. Dies ist offensichtlich weniger ein Problem, wenn Sie beide besitzen Seiten der Gleichung, oder wenn Aufruf ‚base.xxx‘ Teil Ihres Unter Mitglied ist.

  • Wenn Sie eigentlich tun besitzen beiden Seiten der Basis / Unterklasse Gleichung, dann sollten Sie in der Lage sein, eine überschaubare Lösung als institutionalisierte Versteck / Abschattung zu entwickeln.

Ich würde sagen, dass wenn Sie eine Code-Basis haben, die Sie dies tun wollen, sind mit, es ist nicht die beste entworfene Code-Basis. Es ist in der Regel ein Zeichen für eine Klasse in einer Ebene der Hierarchie eine gewisse öffentliche Signatur, während eine andere Klasse von dieser Klasse es braucht nicht abgeleitet benötigen.

Ein bevorstehendes Codierungs Paradigma „Komposition über Vererbung“ bezeichnet. Dies spielt direkt aus den Prinzipien der objektorientierten Entwicklung (insbesondere das Einzel Prinzip Verantwortung und Offen / Geschlossen-Prinzip).

Leider ist die Art und Weise viele von uns Entwickler Objektorientierung gelehrt wurden, haben wir eine Gewohnheit sofort Gedanken über Vererbung statt Zusammensetzung gebildet. Wir neigen dazu, größere Klassen, die viele verschiedene Aufgaben einfach haben, weil sie mit dem gleichen „Real World“ Objekt enthalten sein könnten. Dies kann zu Klassenhierarchien führen, die 5 + Ebenen tief sind.

Ein unglücklicher Nebeneffekt, dass Entwickler normalerweise nicht denken, wenn mit Vererbung zu tun ist, dass Vererbung bildet eine der stärksten Formen von Abhängigkeiten, die Sie jemals in Ihren Code einführen können. Ihre abgeleitete Klasse ist jetzt stark abhängig von der Klasse aus geerbt wurde. Dies kann Ihren Code spröder auf langer Sicht und führt zu verwirrenden Problemen machen, wo ein bestimmtes Verhalten in einer Basisklasse Pausen abgeleiteten Klassen in schwer nachvollziehbarer Weise zu verändern.

Eine Möglichkeit, den Code bis zu brechen ist durch Schnittstellen wie in einer anderen Antwort erwähnt. Dies ist ein intelligentes, was sowieso zu tun, wie Sie eine Klasse externe Abhängigkeiten zu Abstraktionen binden mögen, nicht konkret / abgeleiteten Typen. Auf diese Weise können Sie die Implementierung ändern, ohne die Schnittstelle zu ändern, alles ohne eine einzige Zeile Code in der abhängigen Klasse zu bewirken.

Ich würde viel lieber als ein System mit hunderten / Tausende / noch mehr Klassen zu halten, die alle klein sind und lose gekoppelten, als sich mit einem System, das starken Gebrauch von Polymorphismus / Vererbung macht und weniger Klassen, die mehr eng gekoppelt sind, .

Vielleicht am besten Ressource gibt, auf objektorientierte Entwicklung ist Robert C. Martin Buch, Agile Softwareentwicklung, Grundsätze, Muster und Praktiken .

Wenn sie in der ursprünglichen Klasse public definiert sind, können Sie außer Kraft setzen sie nicht in der abgeleiteten Klasse privat. Sie können jedoch die öffentliche Methode machen eine Ausnahme aus, sowie eine eigene Funktion implementieren.

Edit:. Jorge Ferreira ist richtig

Während die Antwort auf die Frage „nein“ ist, gibt es einen Tipp, den ich wünsche hier ankommen, für andere weisen darauf hin, (vorausgesetzt, dass die OP Art von dritten Parteien Montage Zugang anspielte). Wenn andere Personen ein Assembly verweisen, sollte Visual Studio das folgende Attributs sein zu Ehren, damit es nicht in IntelliSense zeigt (versteckt, aber immer noch genannt werden kann, also Vorsicht):

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

Wenn Sie keine andere Wahl hatten, sollten Sie in der Lage sein new auf ein Verfahren zu verwenden, die einen Basistyp Methode verbirgt, kehren => throw new NotSupportedException();, und kombinieren es mit dem Attribut oben.

Ein weiterer Trick, hängt nicht von einer Basisklasse erben, wenn möglich, in dem die Basis eine entsprechende Schnittstelle (zB IList<T> für List<T>) hat. Schnittstellen implementieren „explizit“ wird auch ausblenden, diese Methoden von Intellisense auf dem Klassentyp. Zum Beispiel:

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

Im Fall von var obj = new GoodForNothing() wird die Dispose() Methode auf obj nicht zur Verfügung. Es wird jedoch für jeden zugänglich sein, die ausdrücklich obj zu IDisposable typ wirft.

Darüber hinaus können Sie auch einen Basistyp wickeln, anstatt von ihm erben, dann verstecken einige Methoden:

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...*/
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top