2011-01-27 10 views
8

non sono sicuro se è possibile che ho visto:
Change Attribute's parameter at runtime.
Il mio caso è molto simile, ma sto cercando di modificare l'attributo di una classe in runtime:Modifica classe di attributi sul runtime

[Category("Change me")] 
public class Classic 
{ 
    public string Name { get; set; } 
} 

una delle risposte è stato:

Dim prop As PropertyDescriptor = TypeDescriptor 
    .GetProperties(GetType(UserInfo))("Age") 
Dim att As CategoryAttribute = DirectCast(
    prop.Attributes(GetType(CategoryAttribute)), 
    CategoryAttribute) 
Dim cat As FieldInfo = att.GetType.GetField(
    "categoryValue", 
     BindingFlags.NonPublic Or BindingFlags.Instance) 
cat.SetValue(att, "A better description") 

cambiato in formato più leggibile, grazie a Marc Gravell:

TypeDescriptor.AddAttributes(table, new Category{ Name = "Changed" }); 

Tutto è buono quando si usano TypeDescriptor ma quando si utilizza:

var attrs = (Category[])typeof(Classic).GetCustomAttributes(
    typeof(Category), 
    true); 
attrs[0].Name 

nome ha il testo "mi Cambia".
C'è un modo per modificare questo attributo in fase di esecuzione?

Edit:
Ho bisogno di questo per Linq2Sql nella finestra di progettazione del codice generato è lo schema di DB. Voglio utilizzare lo schema predefinito dell'utente senza utilizzare il mapping XML o modificare il codice generato (la tabella è ancora in fase di sviluppo e cambia frequentemente).

Il codice designer è:

[global::System.Data.Linq.Mapping.TableAttribute(Name="DbSchema.MyTable")] 
public partial class MyTable 

Voglio l'attributo di essere:

[TableAttribute(Name="MyTable")] 

Ora ho scavato nel codice Framework e penso linq2sql utilizza:

TableAttribute[] attrs = (TableAttribute[])typeof(MyTable) 
    .GetCustomAttributes(typeof(TableAttribute), true); 

Quando uso TypeDescriptor per modificare l'attributo, il valore non viene modificato in GetCustomAttributes.

+2

Perché vuoi fare questo? Gli attributi hanno lo scopo di fornire metadati, non molto altro. Perché non prendere l'approccio di avere una "lista delle regole" che è inizialmente popolata dagli attributi e cambiata da lì? – vcsjones

+0

Cosa stai cercando di ottenere? Localizzare il testo nella categoria? –

+0

@vcsjones ci crediate o no, ci sono momenti in cui è necessario aggiungere, modificare o eliminare gli attributi in fase di esecuzione. Ho dovuto farlo per aggiungere un convertitore ai binding WPF in modo che fossero serializzati invece di essere valutati. – Will

risposta

0

Se si utilizza riflessione, quindi non proprio come questo - riflessione attributi non possono essere sostituiti - solo la componente modello vista è influenzato da TypeDescriptor. Tuttavia, è possibile sottoclasse CategoryAttribute ai propri scopi. Particolarmente utile per i18n.

using System.ComponentModel; 
using System; 
[MyCategory("Fred")] 
class Foo { } 
static class Program 
{ 
    static void Main() 
    { 
     var ca = (CategoryAttribute)Attribute.GetCustomAttribute(typeof(Foo), typeof(CategoryAttribute)); 
     Console.WriteLine(ca.Category); 
       // ^^^ writes "I was Fred, but not I'm EVIL Fred" 
    } 
} 
class MyCategoryAttribute : CategoryAttribute 
{ 
    public MyCategoryAttribute(string category) : base(category) { } 
    protected override string GetLocalizedString(string value) 
    { 
     return "I was " + value + ", but not I'm EVIL " + value; 
    } 
} 
+0

Purtroppo non posso modificare l'attributo originale né creare la mia versione. Linq2Sql si aspetta TableAttribute. –

0

È necessario codificare il proprio attributo in modo che supporti i valori di runtime. Ad esempio, gli attributi di convalida supportano l'internazionalizzazione dei messaggi attraverso l'impostazione di un tipo di risorsa e una stringa di risorse in contrasto con la stringa di messaggi statici.

Un altro approccio consiste nell'utilizzare un contenitore IOC come StructureMap o Unity per fornire alcuni oggetti/servizi che forniscono i valori.

Se non si desidera associare l'attributo a un determinato contenitore, utilizzare il wrapper di ServiceLocator comune fornito dal gruppo Patterns and Practices.

2

Evitare la riflessione interamente, è possibile farlo tramite TypeDescriptor:

using System; 
using System.ComponentModel; 
using System.Linq; 
[Category("nice")] 
class Foo { } 
static class Program 
{ 
    static void Main() 
    { 
     var ca = TypeDescriptor.GetAttributes(typeof(Foo)) 
       .OfType<CategoryAttribute>().FirstOrDefault(); 
     Console.WriteLine(ca.Category); // <=== nice 
     TypeDescriptor.AddAttributes(typeof(Foo),new CategoryAttribute("naughty")); 
     ca = TypeDescriptor.GetAttributes(typeof(Foo)) 
       .OfType<CategoryAttribute>().FirstOrDefault(); 
     Console.WriteLine(ca.Category); // <=== naughty 
    } 
} 
+1

Beh, non funziona davvero ogni volta che uso TypeDescriptor ottengo il valore modificato. Ma linq2sql (ciò di cui ho bisogno per) usa (TableAttribute []) table.GetCustomAttributes (typeof (TableAttribute), true) che ottiene il valore originale ... –

Problemi correlati