Limitare l'attributo personalizzato in modo che possa essere applicato solo a tipi specifici in C #?

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

  •  06-07-2019
  •  | 
  •  

Domanda

Ho un attributo personalizzato che viene applicato alle proprietà della classe e alla classe stessa. Ora tutte le classi che devono applicare il mio attributo personalizzato sono derivate da una singola classe di base.

Come posso limitare il mio attributo personalizzato in modo che possa essere applicato solo a quelle classi, che devono derivare dalla mia classe di base? Come posso farlo?

È stato utile?

Soluzione

Accidenti, lo odio quando mi sbaglio ... funziona se definisci l'attributo come protetto tipo annidato della classe 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; }
}

(risposta originale)

Non puoi farlo - almeno, non in fase di compilazione.

Gli attributi possono essere limitati (per esempio) a " class " ;, " struct " ;, " method " ;, " field " ;, etc, ma niente di più granulare.

Naturalmente, poiché gli attributi non fanno nulla da soli (ignorando PostSharp), saranno inerti su altri tipi (e inerti sui tuoi tipi a meno che tu non aggiunga del codice per guardare gli attributi in fase di esecuzione).

Potresti scrivere una regola FxCop, ma sembra eccessivo.

Mi chiedo, tuttavia, se un attributo sia la scelta migliore:

  

Ora tutte le classi che devono applicare il mio attributo personalizzato sono derivate da una singola classe di base.

Se devono applicare il tuo attributo personalizzato, forse una proprietà / metodo abstract (o forse solo virtual ) sarebbe una scelta migliore?

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

Altri suggerimenti

Non sono a conoscenza di alcun modo per farlo con attributi personalizzati.
Un modo migliore sarebbe far sì che le classi implementino un'interfaccia con un vincolo generico

così

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

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

allora la tua classe base lo farebbe

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

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

In questo modo il compilatore applicherà il vincolo in fase di compilazione in modo che solo le classi
derivato da MyBaseClass può implementare l'interfaccia.
L'ho reso abbastanza estensibile definendo una classe MyAttribute ma potresti ovviamente restituire una stringa o un bool se avessi bisogno di qualcosa di più semplice

Ho anche reso privato il membro MyAttribute in modo che le classi derivate non potessero vederlo e modificarlo ma potessero renderlo protetto e consentire l'accesso alle classi derivate, se lo si desidera.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top