Wie verberge ich eine ererbte Eigenschaft in einer Klasse, ohne die ererbte Klasse (Basisklasse) zu ändern?

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

Frage

Wenn ich das folgende Code -Beispiel 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 das Eigentum zu verbergen? Name (Nicht als Mitglied von Classa -Mitgliedern gezeigt) ohne zu ändern ClassBase ?

War es hilfreich?

Lösung

Ich rieche hier einen Codegeruch. Ich bin der Meinung, dass Sie nur eine Basisklasse erben sollten, wenn Sie alle Funktionen dieser Basisklasse implementieren. Was Sie tun, repräsentiert nicht die objektorientierten Prinzipien richtig. Wenn Sie also von Ihrer Basis erben möchten, sollten Sie den Namen implementieren, andernfalls haben Sie Ihr Erbe falsch. Ihre Klasse A sollte Ihre Basisklasse sein und Ihre aktuelle Basisklasse sollte von A erben, wenn Sie dies wollen, nicht umgekehrt.

Jedoch, Nicht zu weit von der direkten Frage zu verfolgen. Wenn du tat Ich möchte "die Regeln" schlagen und den Weg fortsetzen, den Sie gewählt haben - hier ist, wie Sie es gehen können:

Die Konvention besteht darin, die Eigenschaft umzusetzen, aber ein notimplementedException zu werfen, wenn diese Eigenschaft aufgerufen wird - obwohl ich das auch nicht mag. Aber das ist meine persönliche Meinung und es ändert nicht die Tatsache, dass diese Konvention immer noch steht.

Wenn Sie versuchen, die Eigenschaft zu veraltet (und sie in der Basisklasse als virtuell deklariert), können Sie entweder das veraltete Attribut darauf 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;
    }
}

(Bearbeiten: Wie Brian in den Kommentaren betonte, verursacht der zweite Parameter des Attributs einen Compiler -Fehler, wenn jemand auf die Namenseigenschaft verweist. Daher können sie es nicht verwenden, obwohl Sie ihn in abgeleiteter Klasse implementiert haben.)

Oder wie ich bereits erwähnt habe, verwenden Sie die NotimplementedException:

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

Wenn jedoch die Immobilie nicht Als virtuell deklariert, 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 veraltete Attribut weiterhin auf die gleiche Weise verwenden, als wäre die Methode überschrieben, oder Sie können die beobachtete OptionedException werfen, was auch immer Sie wählen. 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; }

Je nachdem, ob es in der Basisklasse als virtuell deklariert wurde oder nicht.

Andere Tipps

Technisch gesehen wird die Eigenschaft nicht versteckt, aber eine Möglichkeit, ihre Verwendung nachdrücklich zu entmutigen, besteht darin, Attribute wie diese zu setzen:

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

Dies ist, was System.Windows.Forms für Steuerelemente mit Eigenschaften tut, die nicht passen. Das Text Die Eigenschaft zum Beispiel hat die Kontrolle, ist jedoch bei jeder Klasse, die von der Kontrolle erbt, keinen Sinn. Also in MonatCalendar, Zum Beispiel wird die Texteigenschaft wie diese angezeigt (gemäß der Online -Referenzquelle):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • Browsable - Ob das Mitglied im Eigenschaftenfenster auftaucht
  • EditorBrowsable - Ob das Mitglied im IntelliSense -Dropdown auftaucht

EditorBrowsable (False) hindert Sie nicht daran, die Eigenschaft einzugeben, und wenn Sie die Eigenschaft verwenden, wird Ihr Projekt weiterhin kompiliert. Da das Eigentum jedoch nicht in IntelliSense erscheint, wird es nicht so offensichtlich sein, dass Sie es verwenden können.

Verstecke 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: Der Name wird weiterhin ein öffentliches Mitglied von ClassBase sein, da die Basisklasse nicht geändert wird, gibt es keine Möglichkeit, dies zu stoppen.

Warum Erbschaft zwingen, wenn es nicht notwendig ist? Ich denke, die richtige Art, dies zu tun, besteht darin hat ein anstelle einer ist ein.

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

Ich stimme voll und ganz zu, dass Eigenschaften nicht aus Basisklassen entfernt werden sollten, aber manchmal kann eine abgeleitete Klasse eine andere geeignete Möglichkeit haben, die Werte einzugeben. In meinem Fall beispielsweise erbe ich von itemsControl. Wie wir alle wissen, verfügt ItemsControl über die ElementSource -Eigenschaft, aber ich möchte, dass meine Kontrolle Daten aus 2 Quellen (z. B. Person und Standort) verschmelzen. Wenn ich den Benutzer die Daten mit itemsSource eingeben würde, müsste ich die Werte trennen und dann rekombinieren, daher habe ich 2 Eigenschaften erstellt, um die Daten einzugeben. Aber zurück zur ursprünglichen Frage bleibt die ElementSource, die ich nicht verwenden soll, weil ich sie durch meine eigenen Eigenschaften "ersetze". Ich mag die Browsable- und EditorBrowsable -Ideen, aber es hindert der Benutzer immer noch nicht daran, sie zu verwenden. Der Grundpunkt hier ist, dass die Vererbung die meisten Eigenschaften behalten sollte, aber wenn es eine große komplexe Klasse gibt (insbesondere solche, in denen Sie den ursprünglichen Code nicht ändern können), wäre es sehr ineffizient, alles umzuschreiben.

Ich glaube nicht, dass viele Leute, die hier antworten, die Erbschaft überhaupt verstehen. Es besteht die Notwendigkeit, von einer Basisklasse aus zu erben und ihre einst öffentlichen VARs und Funktionen zu verbergen. Angenommen, Sie haben einen einfachen Motor und möchten einen neuen Motor erstellen, der aufgeladen ist. Nun, 99% der Engine, die Sie verwenden, aber Sie werden ein wenig von seiner Funktionalität optimieren, damit sie viel besser ausgeführt werden, und dennoch gibt es einige Funktionen, die nur den vorgeschlagenen Änderungen und nicht dem Endbenutzer angezeigt werden sollten. Weil wir alle wissen, dass jede Klasse, die MS veröffentlicht, keine Änderungen benötigt.

Neben dem Neuen, um einfach die Funktionalität zu überschreiben, ist es eines der Dinge, die Microsoft in ihren unendlichen Wis… .. Oh, ich meine, Fehler, die als Tool, das sich nicht mehr lohnt, angesehen werden.

Der beste Weg, dies jetzt zu erreichen, ist ein mehrstufiges Vererbung.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

Klasse B macht alle Ihre Arbeit und Klasse C, was Sie benötigen, was Sie benötigen.

Sie können nicht, das ist der springende Vererbungspunkt: Die Unterklasse muss alle Methoden und Eigenschaften der Basisklasse anbieten.

Sie könnten die Implementierung ändern, um eine Ausnahme zu werfen, wenn die Eigenschaft aufgerufen wird (falls sie virtuell wäre) ...

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

Wieso den?

Gutes Design besteht darin, die Basisklasse gemeinsame Eigenschaften zu teilen, die ein bestimmtes Konzept hat (virtuell oder real). Beispiel: System.io.stream in C#.

Weiter unten wird das schlechte Design die Kosten für die Wartung erhöhen und die Implementierung immer schwieriger machen. 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; Legen Sie es dann nicht in die Basisklasse. Wenn Sie sich in der Entwicklungsstufe eines Projekts befinden; Gehen Sie jetzt immer zurück zum Salzbrett, um das Design zu überprüfen, weil sich die Dinge ändern! Bei Bedarf neu gestalten. Wenn Ihr Projekt live ist, werden die Kosten für die spätere Änderung der Dinge im Design steigen!

    • Wenn Sie eine von einer 3: RD -Partei implementierte Basisklasse verwenden, sollten Sie "GO up" eine Ebene anstatt mit "NotimplementedException" oder so "überschreiben". Wenn es keine andere Ebene gibt, sollten Sie den Code von Grund auf neu gestalten.

    • Betrachten Sie immer, dass Sie Kurse versiegeln, von denen Sie nicht möchten, dass jemand ihn erben kann. Es zwingt die Codierer, in der "Erbschaftshierarchie" eine Ebene zu erreichen, und so kann "lose Enden" wie "NotimplementedException" vermieden werden.

Ich weiß, dass die Frage alt ist, aber Sie können die 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");
    }

Sie können verwenden Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top