it-swarm.com.de

Wie verbergen Sie eine geerbte Eigenschaft in einer Klasse, ohne die geerbte Klasse (Basisklasse) zu ändern?

Wenn ich folgendes Codebeispiel habe:

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA : ClassBase
{
    public int JustNumber { get; set; }

    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}

Was soll ich tun, um die Eigenschaft Name (nicht als Mitglied von ClassA-Mitgliedern angezeigt) auszublenden, ohne ClassBase zu ändern?

39
Ahmed Magdy

Ich rieche hier einen Code-Geruch. Meines Erachtens sollten Sie eine Basisklasse nur erben, wenn Sie die gesamte Funktionalität dieser Basisklasse implementieren. Was Sie tun, repräsentiert objektorientierte Prinzipien nicht richtig. Wenn Sie also von Ihrer Basis erben möchten, sollten Sie Name implementieren, andernfalls haben Sie Ihre Vererbung falsch herum. Ihre Klasse A sollte Ihre Basisklasse sein, und Ihre aktuelle Basisklasse sollte von A erben, wenn Sie das möchten, nicht umgekehrt.

Allerdings nicht zu weit von der direkten Frage abweichen. Wenn Sie did die Regeln nicht einhalten möchten und den von Ihnen gewählten Pfad fortsetzen möchten, gehen Sie wie folgt vor:

Die Konvention besteht darin, die Eigenschaft zu implementieren, aber eine NotImplementedException auszulösen, wenn diese Eigenschaft aufgerufen wird - auch wenn mir das nicht gefällt. Aber das ist meine persönliche Meinung und es ändert nichts daran, dass diese Konvention immer noch besteht.

Wenn Sie versuchen, die Eigenschaft zu veralten (und in der Basisklasse als virtuell deklariert), können Sie entweder das Attribut Obsolete verwenden:

[Obsolete("This property has been deprecated and should no longer be used.", true)]
public override string Name 
{ 
    get 
    { 
        return base.Name; 
    }
    set
    {
        base.Name = value;
    }
}

( Edit: Wie Brian in den Kommentaren darauf hingewiesen hat, verursacht der zweite Parameter des Attributs einen Compiler-Fehler, wenn jemand auf die Name-Eigenschaft verweist. Daher kann er sie nicht verwenden, obwohl Sie ihn implementiert haben in abgeleiteter Klasse.)

Oder wie gesagt, verwenden Sie NotImplementedException:

public override string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

Wenn jedoch die Eigenschaft nicht als virtuell deklariert ist, können Sie das neue Schlüsselwort verwenden, um es zu ersetzen:

public new string Name
{
    get
    {
        throw new NotImplementedException();
    }
    set
    {
        throw new NotImplementedException();
    }
}

Sie können das Obsolete-Attribut immer noch auf dieselbe Weise verwenden, als wäre die Methode überschrieben worden, oder Sie können die NotImplementedException auslösen, je nachdem, was Sie möchten. Ich würde wahrscheinlich verwenden:

[Obsolete("Don't use this", true)]
public override string Name { get; set; }

oder:

[Obsolete("Don't use this", true)]
public new string Name { get; set; }

Abhängig davon, ob er in der Basisklasse als virtuell deklariert wurde.

54
BenAlabaster

Während die Eigenschaft technisch nicht ausgeblendet wird, besteht eine Möglichkeit, die Verwendung dieser Eigenschaft dringend zu unterbinden, darin, Attribute wie folgt anzugeben:

[Browsable(false)]
[Bindable(false)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
[EditorBrowsable(EditorBrowsableState.Never)]

Dies ist, was System.Windows.Forms für Steuerelemente ausführt, deren Eigenschaften nicht passen. Die Eigenschaft Text befindet sich beispielsweise in Control, ist aber für jede Klasse, die von Control erbt, nicht sinnvoll. So sieht es beispielsweise in MonthCalendar folgendermaßen aus (pro Reflektor):

[Browsable(false), Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
    EditorBrowsable(EditorBrowsableState.Never)]
public override string Text
{
    get { return base.Text; }
    set { base.Text = value; }
}

Durchsuchbar gibt an, ob das Mitglied im Eigenschaftsfenster angezeigt wird. EditorBrowsable gibt an, ob es in der Intellisense-Dropdown-Liste angezeigt wird. Sie können die Eigenschaft weiterhin eingeben, wenn für EditorBrowsable der Wert false festgelegt ist und der Build weiterhin erstellt wird. Es ist jedoch nicht so offensichtlich, dass Sie sie verwenden können.

27
Ryan Lundy

Versteck es einfach 

 public class ClassBase
{
    public int ID { get; set; }
    public string Name { get; set; }
}
public class ClassA : ClassBase
{
    public int JustNumber { get; set; }
    private new string Name { get { return base.Name; } set { base.Name = value; } }
    public ClassA()
    {
        this.ID = 0;
        this.Name = string.Empty;
        this.JustNumber = 0;
    }
}

Hinweis: Name wird weiterhin ein öffentliches Mitglied von ClassBase sein, da die Basisklasse nicht geändert werden muss.

22
CCondron

Warum Erbschaft erzwingen, wenn es nicht notwendig ist? Ich denke, der richtige Weg, dies zu tun, besteht darin, hat-a anstelle von is-a .

public class ClassBase
{
    public int ID { get; set; }

    public string Name { get; set; }
}

public class ClassA
{
    private ClassBase _base;

    public int ID { get { return this._base.ID; } }

    public string JustNumber { get; set; }

    public ClassA()
    {
        this._base = new ClassBase();
        this._base.ID = 0;
        this._base.Name = string.Empty;
        this.JustNumber = string.Empty;
    }
}
4
flayn

Ich glaube nicht, dass viele der Leute, die hier antworten, Erbschaft überhaupt verstehen. Es ist notwendig, von einer Basisklasse zu erben und deren einmalige öffentliche var und Funktionen auszublenden. Beispiel: Nehmen wir an, Sie haben eine Basis-Engine und möchten eine neue Engine erstellen, die aufgeladen ist. Nun, 99% der Engine werden Sie verwenden, aber Sie werden ein wenig von seiner Funktionalität anpassen, damit sie viel besser läuft, und trotzdem gibt es einige Funktionen, die nur für die vorgenommenen Änderungen angezeigt werden sollten, nicht für den Endbenutzer. Weil wir alle wissen, dass jede Klasse, die MS herausbringt, wirklich keine Änderungen benötigt. 

Abgesehen davon, dass das neue Feature verwendet wird, um die Funktionalität einfach zu überschreiben, ist es eines der Dinge, die Microsoft in all seinen unendlichen Wis ... Oh, ich meine Fehler, die als Werkzeug angesehen werden, das sich nicht mehr lohnt. 

Der beste Weg, dies jetzt zu erreichen, ist mehrstufige Vererbung. 

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

Klasse B erledigt all Ihre Arbeit und Klasse C macht das, was Sie brauchen, sichtbar. 

3
engnrman

Ich stimme vollkommen zu, dass Eigenschaften nicht aus Basisklassen entfernt werden sollten, aber manchmal kann eine abgeleitete Klasse einen anderen geeigneten Weg für die Eingabe der Werte haben. In meinem Fall erbe ich zum Beispiel von ItemsControl. Wie wir alle wissen, verfügt ItemsControl über die ItemsSource-Eigenschaft, aber ich möchte, dass mein Steuerelement Daten aus zwei Quellen zusammenführt (z. B. Person und Ort). Wenn der Benutzer die Daten mithilfe von ItemsSource eingeben soll, muss ich die Werte trennen und neu kombinieren. Daher habe ich zwei Eigenschaften erstellt, um die Daten einzugeben. Zurück zu der ursprünglichen Frage bleibt jedoch die ItemsSource, die der Benutzer nicht verwenden soll, da ich sie durch meine eigenen Eigenschaften "ersetze". Ich mag die Ideen von Browsable und EditorBrowsable, die den Benutzer jedoch nicht daran hindern. Der grundlegende Punkt hier ist, dass Vererbung MOST der Eigenschaften beibehalten sollte. Wenn es jedoch eine große komplexe Klasse gibt (insbesondere wenn Sie den ursprünglichen Code nicht ändern können), wäre das Umschreiben alles sehr ineffizient.

2
Nathan Sokalski

Das ist nicht der Punkt der Vererbung: Die Unterklasse muss alle Methoden und Eigenschaften der Basisklasse bereitstellen.

Sie können die Implementierung so ändern, dass beim Aufruf der Eigenschaft eine Ausnahme ausgelöst wird (wenn sie virtuell wäre).

1
Fried Hoeben

Ich weiß, dass die Frage alt ist, aber Sie können PostFilterProperties wie folgt überschreiben:

 protected override void PostFilterProperties(System.Collections.IDictionary properties)
    {
        properties.Remove("AccessibleDescription");
        properties.Remove("AccessibleName");
        properties.Remove("AccessibleRole");
        properties.Remove("BackgroundImage");
        properties.Remove("BackgroundImageLayout");
        properties.Remove("BorderStyle");
        properties.Remove("Cursor");
        properties.Remove("RightToLeft");
        properties.Remove("UseWaitCursor");
        properties.Remove("AllowDrop");
        properties.Remove("AutoValidate");
        properties.Remove("ContextMenuStrip");
        properties.Remove("Enabled");
        properties.Remove("ImeMode");
        //properties.Remove("TabIndex"); // Don't remove this one or the designer will break
        properties.Remove("TabStop");
        //properties.Remove("Visible");
        properties.Remove("ApplicationSettings");
        properties.Remove("DataBindings");
        properties.Remove("Tag");
        properties.Remove("GenerateMember");
        properties.Remove("Locked");
        //properties.Remove("Modifiers");
        properties.Remove("CausesValidation");
        properties.Remove("Anchor");
        properties.Remove("AutoSize");
        properties.Remove("AutoSizeMode");
        //properties.Remove("Location");
        properties.Remove("Dock");
        properties.Remove("Margin");
        properties.Remove("MaximumSize");
        properties.Remove("MinimumSize");
        properties.Remove("Padding");
        //properties.Remove("Size");
        properties.Remove("DockPadding");
        properties.Remove("AutoScrollMargin");
        properties.Remove("AutoScrollMinSize");
        properties.Remove("AutoScroll");
        properties.Remove("ForeColor");
        //properties.Remove("BackColor");
        properties.Remove("Text");
        //properties.Remove("Font");
    }
0
Nane

Sie können Browsable(false) verwenden.

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
0

Ich denke, es ist ein schlechtes Design, wenn Sie dies tun müssen, insbesondere wenn Sie den Code von Grund auf entwerfen können.

Warum?

Ein gutes Design besteht darin, die Basisklasse gemeinsame Eigenschaften eines bestimmten Konzepts (virtuell oder real) gemeinsam nutzen zu lassen. Beispiel: System.IO.Stream in C #.

Weiter unten auf der Fahrspur erhöht ein schlechtes Design die Wartungskosten und macht die Implementierung schwieriger und schwieriger. Vermeiden Sie dies so viel wie möglich! 

Grundregeln, die ich verwende:

  • Minimieren Sie die Anzahl der Eigenschaften und Methoden in der Basisklasse. Wenn Sie nicht erwarten, einige Eigenschaften oder Methoden in einer Klasse zu verwenden, die die Basisklasse erbt. dann nicht in die baseclass stecken. Wenn Sie sich in der Entwicklungsphase eines Projekts befinden; Gehen Sie jetzt immer zurück zum Zeichenbrett, um das Design zu überprüfen, da sich die Dinge ändern! Bei Bedarf umgestalten. Wenn Ihr Projekt live läuft, steigen die Kosten für spätere Änderungen im Design!

    • Wenn Sie eine Baseclass verwenden, die von einer dritten Partei implementiert wurde, sollten Sie eine Stufe höher gehen, anstatt sie mit "NotImplementedException" oder ähnlichem zu "überschreiben". Wenn es keine andere Ebene gibt, sollten Sie den Code von Grund auf entwerfen.

    • Denken Sie immer daran, Klassen zu versiegeln, von denen niemand will, dass sie sie erben können. Es zwingt die Codierer, in der "Vererbungshierarchie" eine Stufe nach oben zu gehen, und so können "lose Enden" wie "NotImplementedException" vermieden werden.

0
user3567581