Restreindre l'attribut personnalisé afin qu'il ne puisse être appliqué qu'à des types spécifiques en C #?

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

  •  06-07-2019
  •  | 
  •  

Question

J'ai un attribut personnalisé qui est appliqué aux propriétés de classe et à la classe elle-même. Désormais, toutes les classes qui doivent appliquer mon attribut personnalisé sont dérivées d'une seule classe de base.

Comment puis-je restreindre mon attribut personnalisé afin qu'il ne puisse être appliqué qu'aux classes qui doivent provenir de ma classe de base? Comment je fais ça?

Était-ce utile?

La solution

Zut, je déteste quand je prouve que j'ai tort. Cela fonctionne si vous définissez l'attribut comme un type imbriqué protected de la classe de base:

abstract class MyBase {
    [AttributeUsage(AttributeTargets.Property)]
    protected sealed class SpecialAttribute : Attribute {}
}

class ShouldBeValid : MyBase {
    [Special]
    public int Foo { get; set; }
}
class ShouldBeInvalid {
    [Special] // type or namespace not found
    [MyBase.Special] // inaccessible due to protection level
    public int Bar{ get; set; }
}

(réponse originale)

Vous ne pouvez pas faire cela - du moins, pas au moment de la compilation.

Les attributs peuvent être restreints (par exemple) à "classe", "struct", "méthode", "champ", etc. - mais rien de plus granulaire.

Bien sûr, étant donné que les attributs ne font rien par eux-mêmes (en ignorant PostSharp), ils seront inertes sur les autres types (et inertes sur vos types, sauf si vous ajoutez du code pour examiner les attributs à l'exécution).

Vous pouvez écrire une règle FxCop, mais cela semble excessif.

Je me demande toutefois si un attribut est le meilleur choix:

  

Toutes les classes qui doivent appliquer mon attribut personnalisé sont dérivées d'une classe de base unique.

S'ils doivent appliquer votre attribut personnalisé, une propriété / méthode abstract (ou peut-être simplement virtual ) serait-elle un meilleur choix?

abstract class MyBase {
    protected abstract string GetSomeMagicValue {get;}
}
class MyActualType : MyBase {
    protected override string GetSomeMagicValue {get {return "Foo";}}
}

Autres conseils

Je ne connais aucun moyen de faire cela avec des attributs personnalisés.
Un meilleur moyen serait de faire en sorte que les classes implémentent une interface avec une contrainte générique

alors

class MyAttribute
{
     // put whatever custom data you want in here
}

interface IAttributeService<T> where T : MyBaseClass
{
     MyAttribute Value{get;}
}

alors votre classe de base le ferait

class MyBaseClass : IAttributeService<MyBaseClass>
{
     private MyAttribute m_attrib;

     IAttributeService<MyClass>.Value
     {
         get {return m_attrib;}
     }
}

Ainsi, le compilateur appliquera la contrainte lors de la compilation, de sorte que seules les classes
dérivé de MyBaseClass peut implémenter l'interface.
Je l'ai rendu assez extensible en définissant une classe MyAttribute mais vous pouvez bien sûr simplement renvoyer une chaîne ou un bool si vous aviez besoin de quelque chose de plus simple

J'ai également rendu le membre MyAttribute privé afin que les classes dérivées ne puissent pas le voir et le changer, mais qu'il soit protégé et autorise l'accès aux classes dérivées si vous le souhaitez.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top