Come nascondere una proprietà ereditata in una classe senza modificare la classe ereditata (classe di base)?

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

Domanda

Se ho il seguente esempio di codice:

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

Cosa devo fare per nascondere la Name proprietà (Non mostrato come membro dei membri ClassA) senza modificare ClassBase?

È stato utile?

Soluzione

Sento odore di un odore di codice qui. E 'mia opinione che si dovrebbe ereditare una classe di base se si sta implementando tutte le funzionalità di quella classe di base. Quello che stai facendo in realtà non rappresentano oggetto principi orientati correttamente. Quindi, se si vuole ereditare da vostra base, si dovrebbe essere implementando nome, altrimenti hai la tua eredità nel modo sbagliato. La classe A dovrebbe essere la vostra base di classe e la classe corrente di base dovrebbe ereditare da A, se questo è ciò che si vuole, non il contrario.

Tuttavia, per non allontanarsi troppo dalla domanda diretta. Se ha vogliono violare "le regole" e vuole continuare sulla strada che avete scelto - ecco come si può andare a questo proposito:

La convenzione è quello di implementare la proprietà, ma gettare un NotImplementedException quando la proprietà viene chiamata - anche se, non mi piace nemmeno questo. Ma questa è la mia opinione personale e non cambia il fatto che questa convenzione si trova ancora.

Se si sta tentando di obsoleta la proprietà (ed è dichiarato nella classe di base come virtuale), allora si potrebbe usare sia l'attributo obsoleto su di esso:

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

( Modifica Come Brian ha sottolineato nei commenti, il secondo parametro dell'attributo causerà un errore di compilazione se qualcuno fa riferimento la proprietà Name, quindi non saranno in grado di utilizzarlo anche se hai implementato in classe derivata.)

O, come ho già detto uso NotImplementedException:

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

Tuttavia, se la proprietà non è ha dichiarato come virtuale, quindi è possibile utilizzare la nuova parola chiave per sostituirlo:

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

È comunque possibile utilizzare l'attributo obsoleto nello stesso modo come se il metodo è stato sovrascritto, o si può buttare la NotImplementedException, a seconda di quale si sceglie. Io probabilmente usare:

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

o

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

A seconda se o non è stata dichiarata come virtuale nella classe base.

Altri suggerimenti

Anche se tecnicamente la proprietà non sarà nascosto, un modo per scoraggiare fortemente il suo uso è quello di mettere gli attributi su di esso come questi:

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

Questo è ciò che fa System.Windows.Forms per i controlli che hanno proprietà che non si adattano. Il testo di proprietà, per esempio, è il controllo, ma non ha senso in ogni classe che eredita da Control. Quindi, in MonthCalendar , per esempio, la proprietà Text appare come questa (per la fonte di riferimento on-line):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • sfogliabile - se gli Stati si presenta nella finestra Proprietà
  • EditorBrowsable - se gli Stati si presenta nel menu a discesa Intellisense

EditorBrowsable (false) non impedirà di digitare la proprietà, e se si utilizza la proprietà, il progetto sarà ancora la compilazione. Ma dal momento che la proprietà non appare in Intellisense, non sarà così evidente che si può utilizzare.

Proprio nasconderlo

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

Nota: Nome sarà ancora un membro pubblico di ClassBase, dato il vincolo di non cambiare la classe base non c'è modo di fermare quel

.

Perché la forza di successione quando non è necessario? Penso che il modo corretto di farlo è quello di eseguire ha-un al posto di un 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;
    }
}

Sono completamente d'accordo che le proprietà non deve essere rimosso da classi base, ma a volte una classe derivata potrebbe avere un diverso modo più appropriato per immettere i valori. Nel mio caso, per esempio, sto eredita da ItemsControl. Come tutti sappiamo, ItemsControl ha la proprietà ItemsSource, ma voglio il mio controllo per unire i dati da 2 fonti (ad esempio, Persona e posizione). Se dovessi avere all'utente di inserire i dati utilizzando ItemsSource, avrei bisogno di separare e poi ricombinare i valori, così ho creato 2 proprietà per inserire i dati. Ma torniamo alla domanda iniziale, questo lascia l'ItemsSource, che io non voglio all'utente di utilizzare perché sono "sostituire" con i miei proprietà. Mi piacciono le idee sfogliabili e EditorBrowsable, ma ancora non impedisce all'utente di utilizzarlo. Il punto fondamentale è che l'ereditarietà dovrebbe mantenere la maggioranza delle proprietà, ma quando c'è un grande complesso di classe (soprattutto quelli in cui non è possibile modificare il codice originale), riscrivendo tutto sarebbe molto inefficiente.

Non credo che un sacco di persone che hanno risposto qui capire eredità a tutti. V'è la necessità di ereditare da una classe di base e nascondere e le funzioni del suo var volta pubblico. Esempio, Diciamo che avere un motore di base e si vuole fare un nuovo motore che è sovralimentato. Ebbene, il 99% del motore che si utilizzerà, ma si modificherà un po 'della sua funzionalità per farlo funzionare molto meglio ma ancora non v'è alcune funzionalità che dovrebbe essere mostrata solo per le modifiche apportate, non l'utente finale. Perché tutti sappiamo che ogni classe MS mette fuori in realtà non mai bisogno eventuali modifiche.

Oltre a utilizzare la nuova di ignorare semplicemente la funzionalità che è una delle cose che Microsoft nelle loro infinite WIS ... .. oh, voglio dire gli errori considerati più uno strumento non vale la pena.

Il modo migliore per raggiungere questo obiettivo è ora multi-livello eredità.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

Classe B fa tutto il vostro lavoro e la classe C espone quello che ti serve esposti.

Non è possibile, che è il punto di eredità: la sottoclasse deve offrire tutti i metodi e le proprietà della classe di base

.

Si potrebbe modificare l'implementazione un'eccezione quando la proprietà viene chiamata (se fosse virtuale) ...

Credo che sia una cattiva progettazione se si ha a che fare questo, soprattutto se si è in grado di progettare il codice da zero.

Perché?

Un buon design è quello di lasciare le proprietà comuni della classe base di condivisione che un certo concetto ha (virtuali o reali). Esempio:. System.IO.Stream in C #

Proseguendo lungo la corsia di cattivo design aumenterà il costo per la manutenzione e rendere implementazione sempre più difficile. Evitare questo il più possibile!

Le regole di base che uso:

  • Minimizzare il numero di proprietà e metodi della classe base. Se non si prevede di utilizzare alcune proprietà o metodi in una classe che eredita la classe di base; non metterlo nei baseclass poi. Se siete nel developmentstage di un progetto; sempre tornare al tavolo da disegno ora un poi di verificare la progettazione perché le cose cambiano! Riprogettare quando necessario. Quando il progetto è vivo i costi per cambiare le cose nel corso della progettazione salirà!

    • Se si utilizza un baseclass implementato da un 3: partito terzo, considerare "salire" di un livello invece di "override" con "NotImplementedException" o simili. Se non c'è altro livello, prendere in considerazione la progettazione del codice da zero.

    • Sempre in considerazione per sigillare le classi che non si desidera a chiunque di essere in grado di ereditare esso. Costringe codificatori a "salire di un livello" nella "gerarchia inheritance-" e quindi "in sospeso" come "NotImplementedException" può essere evitato.

Lo so che la questione è vecchio, ma che cosa si può fare è ignorare i PostFilterProperties in questo modo:

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

È possibile utilizzare Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top