2013-02-02 6 views
33
//Get PropertyDescriptor object for the given property name 
var propDesc = TypeDescriptor.GetProperties(typeof(T))[propName]; 

//Get FillAttributes methodinfo delegate 
var methodInfo = propDesc.GetType().GetMethods(BindingFlags.Instance | BindingFlags.Public | 
                 BindingFlags.NonPublic) 
    .FirstOrDefault(m => m.IsFamily || m.IsPublic && m.Name == "FillAttributes"); 

//Create Validation attribute 
var attribute = new RequiredAttribute(); 
var attributes= new ValidationAttribute[]{attribute}; 

//Invoke FillAttribute method 
methodInfo.Invoke(propDesc, new object[] { attributes }); 

Ciao Sto cercando di aggiungere l'attributo Validation in fase di esecuzione utilizzando il codice precedente. Comunque io sono sempre l'eccezione di seguito:Come aggiungere un attributo a una proprietà in fase di esecuzione

collezione era di dimensioni fisse

+0

possibile duplicato del [Può attributi da aggiungere dinamicamente C#?] (Http://stackoverflow.com/questions/129285/can-attributes-be-added-dynamically-in-c) –

risposta

0

Non è wokring perché FillAttributes metodo si aspetta parametro di tipo IList e si sta passando array. Qui di seguito è la realizzazione di MemberDescriptor.FillAttributes:

protected virtual void FillAttributes(IList attributeList) { 
    if (originalAttributes != null) { 
     foreach (Attribute attr in originalAttributes) { 
      attributeList.Add(attr); 
     } 
    } 
} 

Come si può vedere FillAttributes riempie solo il parametro attributeList con tutti gli attributi della vostra proprietà. E per rendere il vostro lavoro codice di cambiare var attributes= new ValidationAttribute[]{attribute}; linea con:

var attributes = new ArrayList { attribute }; 

Questo codice non ha nulla con l'aggiunta di attributi per proprietà di tipo in fase di esecuzione. Si tratta di "attributo allo PropertyDescriptor" estratto dal tipo e non ha senso a meno che non si stia tentando di creare il tipo in fase di runtime basato sul tipo già esistente.

80

Non lasciare che qualcuno ti dica, non puoi farlo. Si può correre per la presidenza se si vuole :-)

Per la vostra conveniance, questo è un esempio completamente funzionante

public class SomeAttribute : Attribute 
    { 
     public SomeAttribute(string value) 
     { 
      this.Value = value; 
     } 

     public string Value { get; set; } 
    } 

    public class SomeClass 
    { 
     public string Value = "Test"; 
    } 

    [TestMethod] 
    public void CanAddAttribute() 
    { 
     var type = typeof(SomeClass); 

     var aName = new System.Reflection.AssemblyName("SomeNamespace"); 
     var ab = AppDomain.CurrentDomain.DefineDynamicAssembly(aName, AssemblyBuilderAccess.Run); 
     var mb = ab.DefineDynamicModule(aName.Name); 
     var tb = mb.DefineType(type.Name + "Proxy",System.Reflection.TypeAttributes.Public, type); 

     var attrCtorParams = new Type[] { typeof(string) }; 
     var attrCtorInfo = typeof(SomeAttribute).GetConstructor(attrCtorParams); 
     var attrBuilder = new CustomAttributeBuilder(attrCtorInfo, new object[] { "Some Value" }); 
     tb.SetCustomAttribute(attrBuilder); 

     var newType = tb.CreateType(); 
     var instance = (SomeClass)Activator.CreateInstance(newType); 

     Assert.AreEqual("Test", instance.Value); 
     var attr = (SomeAttribute)instance.GetType().GetCustomAttributes(typeof(SomeAttribute), false).SingleOrDefault(); 
     Assert.IsNotNull(attr); 
     Assert.AreEqual(attr.Value, "Some Value"); 

    } 
+23

Thumbs up per la conversazione motivazionale! – Sjoerd222888

+1

Quello che ho imparato da Deez Nuts è che l'aggiunta di un attributo a una proprietà in fase di esecuzione è il modo più difficile :-) –

+1

Hmm, sembra che non possiamo utilizzare questa tecnica per i membri enum. Viene visualizzato un errore che dice che la classe genitore è sigillata ... – Jerther

0

uso FastDeepCloner

public class test{ 
public string Name{ get; set; } 
} 

var prop = now DeepCloner.GetFastDeepClonerProperties(typeof(test)).First(); 
prop.Attributes.Add(new JsonIgnoreAttribute()); 
// now test and se if exist 
prop = now DeepCloner.GetFastDeepClonerProperties(typeof(test)).First(); 
bool containAttr = prop.ContainAttribute<JsonIgnoreAttribute>() 
// or 
JsonIgnoreAttribute myAttr = prop.GetCustomAttribute<JsonIgnoreAttribute>();