Gli attributi possono essere aggiunti in modo dinamico in C #?


143

È possibile aggiungere attributi in fase di esecuzione o modificare il valore di un attributo in fase di esecuzione?

Risposte:


67

Gli attributi sono metadati statici. Assiemi, moduli, tipi, membri, parametri e valori restituiti non sono oggetti di prima classe in C # (ad esempio, la System.Typeclasse è semplicemente una rappresentazione riflessa di un tipo). È possibile ottenere un'istanza di un attributo per un tipo e modificare le proprietà se sono scrivibili ma ciò non influirà sull'attributo quando viene applicato al tipo.


68

Questo dipende davvero da cosa stai esattamente cercando di realizzare.

Le cose System.ComponentModel.TypeDescriptor possono essere usate per aggiungere attributi a tipi, proprietà ed istanze di oggetti, e hanno il limite che devi usarlo per recuperare anche quelle proprietà. Se stai scrivendo il codice che consuma quegli attributi e puoi vivere entro quei limiti, allora lo consiglierei sicuramente.

Per quanto ne so, il controllo PropertyGrid e la superficie di progettazione dello studio visivo sono le uniche cose nel BCL che consumano le cose TypeDescriptor. In effetti, è così che fanno circa la metà delle cose che devono veramente fare.


7
In realtà, la maggior parte degli usi del data binding TypeDescriptor- non solo PropertyGrid.
Marc Gravell

1
Qualche soluzione alternativa per aggiungere attributi di metadati di proprietà in un progetto Silverlight (dove TypeDescriptore TypeDescriptionProvidernon sono implementati?
Shimmy Weitzhandler,

1
È importante notare che TypeDescriptor.GetAttributes () non gestisce gli attributi duplicati. Seleziona solo l'ultimo del tipo di attributo. Si trova [Attr(1), Attr(2), Attr(3)]solo Ex Attr(3).
ohmusama,

11

Non puoi. Una soluzione alternativa potrebbe essere quella di generare una classe derivata in fase di runtime e aggiungere l'attributo, sebbene questo sia probabilmente un po 'eccessivo.


10

Bene, solo per essere diversi, ho trovato un articolo che fa riferimento a Reflection. Ammettilo.

Ecco il link: http://www.codeproject.com/KB/cs/dotnetattributes.aspx , vorrai anche esaminare alcuni dei commenti in fondo all'articolo, perché vengono discussi i possibili approcci.


10
Nota che puoi creare attributi in fase di esecuzione con le classi Reflection.Emit, MA puoi associarli alle classi che hai creato con il pacchetto Emit e non a quelle esistenti.
Panos,

che risposta inutile =)) ci preoccupiamo tutti delle classi esistenti qui, non di quelle dinamiche.
Senza speranza

@Hopeless, puoi sottoclassare YourClassin YourRuntimeClassWithAttributes.
Motes

@Motes non sono sicuro di cosa intendi, le mie classi sono tutte definite in anticipo, ciò significa che anche tutte le classi base (che le mie classi ereditano) dovrebbero essere definite / determinate in anticipo. Non riesco a pensare ad alcun modo per essere coinvolto in qualcosa creato dinamicamente usando Reflection.Emit.
Hopeless

1
@Hopeless, se si desidera aggiungere gli attributi in modo dinamico a una classe esistente YourClass, è possibile sottoclassarlo in fase di esecuzione e generare una classe identica con un nome leggermente diverso che abbia anche gli attributi desiderati creati dinamicamente e il polimorfismo consentirà al codice di controllo del tipo di identificare ancora la tua base.
Motes

4

No non lo è.

Gli attributi sono metadati e archiviati in forma binaria nell'assieme compilato (ecco perché è possibile utilizzare solo tipi semplici in essi).


3

Io non ci credo. Anche se sbaglio, il meglio che puoi sperare è aggiungerli a un intero Tipo, mai un'istanza di un Tipo.


22
TypeDescriptor.AddAttributes (Object, Attribute []) aggiunge attributi a livello di classe all'istanza del componente di destinazione.
Peter vinto il

3

Se hai bisogno di qualcosa per poterlo aggiungere dinamicamente, gli attributi c # non sono la strada giusta. Cerca nella memorizzazione dei dati in XML. Di recente ho realizzato un progetto che ho avviato con attributi, ma alla fine sono passato alla serializzazione con XML.


1
forse non è un bel modo, ma è il modo in cui molte altre biblioteche scelgono di usare, e per personalizzare i comportamenti di quelle biblioteche, abbiamo l'obbligo di giocare con reflection =)) davvero un deadlock.
Senza speranza

3

Perché ne hai bisogno? Gli attributi forniscono informazioni extra per la riflessione, ma se sai esternamente quali proprietà desideri non ne hai bisogno.

È possibile archiviare metadati esternamente relativamente facilmente in un database o in un file di risorse.


1
Eliminazione della piastra della caldaia. Non sarebbe utile se una classe potesse generare automagicamente attributi basati sul codice all'interno della classe? Sto cercando di capire qualcosa del genere per ridurre la piastra di cottura negli oggetti CLR SQL. Sarebbe facile in altre lingue ... vedi paulgraham.com/avg.html
Duncan Bayne

1

Ho provato molto con System.ComponentModel.TypeDescriptor senza successo. Ciò non significa che non possa funzionare, ma mi piacerebbe vedere il codice per quello.

In contropartita, volevo cambiare alcuni valori di attributo. Ho fatto 2 funzioni che funzionano bene a tale scopo.

        // ************************************************************************
        public static void SetObjectPropertyDescription(this Type typeOfObject, string propertyName,  string description)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(DescriptionAttribute)] as DescriptionAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("description", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, description);
                }
            }
        }

        // ************************************************************************
        public static void SetPropertyAttributReadOnly(this Type typeOfObject, string propertyName, bool isReadOnly)
        {
            PropertyDescriptor pd = TypeDescriptor.GetProperties(typeOfObject)[propertyName];
            var att = pd.Attributes[typeof(ReadOnlyAttribute)] as ReadOnlyAttribute;
            if (att != null)
            {
                var fieldDescription = att.GetType().GetField("isReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                if (fieldDescription != null)
                {
                    fieldDescription.SetValue(att, isReadOnly);
                }
            }
        }

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.