Comment cacher une propriété héritée dans une classe sans modifier la classe héritée (classe de base)?

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

Question

Si j'ai l'exemple de code suivant:

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

Que dois-je faire pour cacher la Name propriété (Ne pas présentée comme un membre des membres ClassA) sans modifier ClassBase?

Était-ce utile?

La solution

Je sens une odeur de code ici. Je suis d'avis que vous ne devriez hériter d'une classe de base si vous implémentez toutes les fonctionnalités de cette classe de base. Ce que vous faites ne représente pas vraiment des principes orientés objet correctement. Ainsi, si vous voulez hériter de votre base, vous devriez implémentez Nom, sinon vous avez votre héritage dans le mauvais sens. Votre classe A devrait être votre classe de base et votre classe de base actuelle devrait hériter de A si c'est ce que vous voulez, et non l'inverse.

Cependant, ne pas s'égarer trop loin de la question directe. Si vous ne veulent bafouer « les règles » et veulent continuer sur le chemin que vous avez choisi - voici comment vous pouvez aller à ce sujet:

La convention est de mettre en œuvre la propriété, mais jeter un NotImplementedException quand cette propriété est appelée - bien, je ne l'aime pas non plus. Mais c'est mon opinion personnelle et cela ne change pas le fait que cette convention est toujours valable.

Si vous essayez de la propriété obsolète (et il est déclaré dans la classe de base comme virtuelle), alors vous pouvez soit utiliser l'attribut obsolète sur elle:

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

( Modifier Comme Brian a souligné dans les commentaires, le deuxième paramètre de l'attribut provoquera une erreur de compilation si quelqu'un fait référence à la propriété Name, donc ils ne seront pas en mesure de l'utiliser même si vous avez mis en place dans la classe dérivée.)

Ou, comme je l'ai mentionné l'utilisation NotImplementedException:

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

Cependant, si la propriété ne sont pas a déclaré que virtuelle, vous pouvez utiliser le nouveau mot-clé pour le remplacer:

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

Vous pouvez toujours utiliser l'attribut obsolète de la même manière que si la méthode a été remplacée, ou vous pouvez jeter le NotImplementedException, selon votre choix. J'utiliserais probablement:

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

ou

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

Selon ou non été déclarée comme virtuelle dans la classe de base.

Autres conseils

Bien que techniquement la propriété ne sera pas caché, une façon de décourager fortement son utilisation est de mettre les attributs sur comme ceux-ci:

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

est ce que System.Windows.Forms fait pour les contrôles qui ont des propriétés qui ne correspondent pas. Texte propriété, par exemple, est sur le contrôle, mais il n'a pas de sens à chaque classe qui hérite de Control. Ainsi, dans MonthCalendar , par exemple, la propriété Text apparaît comme celui-ci (par la source de référence en ligne):

[Browsable(false),
    EditorBrowsable(EditorBrowsableState.Never),
    Bindable(false), 
    DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public override string Text {
    get { return base.Text; }
    set { base.Text = value; }
}
  • Browsable - si le membre apparaît dans la fenêtre Propriétés
  • EditorBrowsable - si le membre apparaît dans la liste déroulante IntelliSense

EditorBrowsable (false) ne vous empêchera pas de taper la propriété, et si vous utilisez la propriété, votre projet sera toujours compiler. Mais puisque la propriété ne figure pas dans IntelliSense, il ne sera pas aussi évident que vous pouvez l'utiliser.

Il suffit de le cacher

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

Remarque: Le nom sera toujours membre du public de ClassBase, compte tenu de la contrainte de ne pas changer la classe de base il n'y a pas moyen d'arrêter que

.

Pourquoi l'héritage de force quand il est pas nécessaire? Je pense que la bonne façon de le faire est en faisant a-un au lieu de est-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;
    }
}

Je suis complètement d'accord que les propriétés ne doivent pas être retirés des classes de base, mais parfois une classe dérivée pourrait avoir une autre façon plus appropriée pour entrer les valeurs. Dans mon cas, par exemple, je suis héritant de ItemsControl. Comme nous le savons tous, a la propriété ItemsControl ItemsSource, mais je veux que mon contrôle pour fusionner les données de 2 sources (par exemple, personne et emplacement). Si je devais l'utilisateur à saisir les données à l'aide ItemsSource, je dois séparer et recombiner les valeurs, donc j'ai créé 2 propriétés pour saisir les données. Mais revenons à la question initiale, ce qui laisse la ItemsSource, que je ne veux pas l'utilisateur d'utiliser parce que je suis « remplaçais » avec mes propres propriétés. J'aime les idées et explorables EditorBrowsable, mais il ne reste empêche pas l'utilisateur de l'utiliser. Le point fondamental est que l'héritage devrait conserver la plupart des propriétés, mais quand il y a une grande classe complexe (en particulier les ceux où vous ne pouvez pas modifier le code original), tout réécriture serait très inefficace.

Je ne pense pas que beaucoup de personnes ayant répondu ici comprennent l'héritage du tout. Il est nécessaire d'hériter d'une classe de base et cacher son de var une fois publique et les fonctions. Exemple, disons que vous avez un moteur de base et que vous voulez faire un nouveau moteur suralimenté. Eh bien, 99% du moteur, vous utiliserez mais vous bidouiller un peu de ses fonctionnalités pour le faire fonctionner beaucoup mieux et pourtant il y a certaines fonctionnalités qui ne devrait être démontré que les modifications apportées, et non l'utilisateur final. Parce que nous savons tous que tous les MS de classe met à ne pas vraiment jamais besoin de modifications.

En plus d'utiliser la nouvelle simplement remplacer la fonctionnalité, il est l'une des choses que Microsoft dans leurs wis infinies ... .. oh, je veux dire des erreurs considéré comme un outil utile plus pas.

La meilleure façon d'y arriver est maintenant l'héritage multi-niveaux.

public class classA 
{
}

public class B : A 
{} 

public class C : B 
{} 

Classe B fait tout votre travail et la classe C expose ce que vous devez exposé.

Vous ne pouvez pas, c'est le point entier de l'héritage: la sous-classe doit offrir toutes les méthodes et propriétés de la classe de base

.

Vous pouvez changer la mise en œuvre de lancer une exception lorsque la propriété est appelée (si elle était virtuelle) ...

Je pense qu'il est une mauvaise conception si vous devez le faire, surtout si vous êtes en mesure de concevoir le code à partir du sol.

Pourquoi?

Une bonne conception est de laisser les propriétés d'actions de base de classe commune qu'un certain concept a (virtuel ou réel). Exemple:. System.IO.Stream en C #

Plus loin sur la voie mauvaise conception augmentera le coût de la maintenance et rendre la mise en œuvre plus en plus difficile. Éviter autant que possible!

Les règles de base que j'utilise:

  • Minimiser le nombre de propriétés et méthodes de la classe de base. Si vous ne vous attendez pas à utiliser certaines propriétés ou méthodes dans une classe qui hérite de la classe de base; ne mettez pas dans la classe de base alors. Si vous êtes dans le developmentstage d'un projet; toujours revenir en arrière au dessin à bord maintenant puis de vérifier la conception parce que les choses changent! Refonte en cas de besoin. Lorsque votre projet est en direct les coûts pour changer les choses plus tard dans la conception montera!

    • Si vous utilisez un baseclass mis en œuvre par un 3: tierce partie, pensez à « monter » un niveau au lieu de « remplaçant » par « NotImplementedException » ou tel. S'il n'y a pas d'autre niveau, pensez à concevoir le code à partir de zéro.

    • Il faut toujours considérer pour sceller les classes que vous ne voulez pas que quiconque d'être en mesure d'en hériter. Elle oblige à codeurs « monter d'un niveau » dans la « hiérarchie inheritance- » et donc « en vrac » comme extrémités « NotImplementedException » peut être évité.

Je sais que la question est vieux, mais ce que vous pouvez faire est de passer outre les PostFilterProperties comme ceci:

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

Vous pouvez utiliser Browsable(false)

[Browsable( false )]
public override string Name
{
    get { return base.Name; }
    set { base.Name= value; }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top