none
Add or change attribute to a property in runtime, is it possible ?

    Pregunta

  • Hi,

    I need to change or add  new attribute to a property in run time  (.net 2.0)

    is it possible ?

    I tried  using reflection something like that

    Class2 c2 = new Class2();

    PropertyInfo[] propInfoArray = c2.GetType().GetProperties();

    PropertyInfo myProp = propInfoArray[0];

    MyDisplayNameAttribute myName = (MyDisplayNameAttribute)myProp.GetCustomAttributes(true)[0];

    myName.SetNewDisplayValue("Hello 2");

    lunes, 24 de julio de 2006 7:31

Respuestas

  • No, this is not possible. Remember, attributes are stored in the DLL or EXE that defines the class. So to change the value of an attribute, you are essentially asking to edit that DLL or EXE. Applications typically cannot change their own binaries while they are running.

    Also, bear in mind that attributes are per-class. So although the intent of your code appears to be to adjust an attribute of the instance you've created here, that wouldn't work. Even if you were able to change attribute values at runtime, you wouldn't be able to change them per-instance, because attributes are a class-level feature, not an instance-level feature.

    What are you trying to do? The technique you propose isn't going to work, so you'll need to find a different solution. But without knowing what your goal is, it's hard to suggest anything useful. Were you hoping to add new properties to an object at runtime like you can in Python or Ruby?

    lunes, 24 de julio de 2006 8:39

Todas las respuestas

  • No, this is not possible. Remember, attributes are stored in the DLL or EXE that defines the class. So to change the value of an attribute, you are essentially asking to edit that DLL or EXE. Applications typically cannot change their own binaries while they are running.

    Also, bear in mind that attributes are per-class. So although the intent of your code appears to be to adjust an attribute of the instance you've created here, that wouldn't work. Even if you were able to change attribute values at runtime, you wouldn't be able to change them per-instance, because attributes are a class-level feature, not an instance-level feature.

    What are you trying to do? The technique you propose isn't going to work, so you'll need to find a different solution. But without knowing what your goal is, it's hard to suggest anything useful. Were you hoping to add new properties to an object at runtime like you can in Python or Ruby?

    lunes, 24 de julio de 2006 8:39
  • 10x IanG

    I need to display in a Propertygrid control a component properties, BUT the original name of the properties is no good for me.I need to localize them.

    for that i used ITypeDescriptorFilterService.FilterProperties that solved the problem except ExtendedProperty that don't change the display name.

    after looking in reflection of Memberdescriptor i saw

    public virtual string DisplayName
    {
          get
          {
                DisplayNameAttribute attribute1 = this.Attributes[typeof(DisplayNameAttribute)] as DisplayNameAttribute;
                if ((attribute1 != null) && !attribute1.IsDefaultAttribute())
                {
                      return attribute1.DisplayName;
                }
                return this.displayName;
          }
    }
    so my thoughts was to add DisplayNameAttribute to each one of my properties. 

    lunes, 24 de julio de 2006 8:54
  • OK, the PropertyGrid uses the the member virtualization facility provided by the TypeDescriptor family of classes. So while it's not possible to change attributes or add new properties at runtime, it is possible to change what properties the TypeDescriptor lists for your class.

    Changing the name of properties as they appear in the PropertyGrid is an explicitly supported scenario, but you don't do it the way you're trying to.

    In the highly unlikely event that you have access to a copy of my book, ".NET Windows Forms in a Nutshell" (published by O'Reilly), you'll find an example on pages 232-238 - it walks through the localization of properties on a property grid. But assuming you don't have a copy,  here's what you need to do.

    It sounds like you're most of the way there, and have got stuck on the fact that MemberDescriptor almost does what you need but not quite. Unfortunately you need to write your own PropertyDescriptor class. You can't just change a property on the built in one - you need to supply your own that overrides DisplayName. (That's why DisplayName is virtual by the way.)

    The simplest option is to derive from TypeConverter.SimplePropertyDescriptor - this does most of the work for you. (Although it's a protected nested class, so you have do define your custom descriptor as a nested class of a custom TypeConverter. That might not be a problem, because to customize the property metadata for a single property, you'll already need to write a custom TypeConverter. However, it sounds like you may have gone down the other path - customizing the type descriptions at the class level, in which case this might be less convenient.)

    If you can derive from TypeConverter.SimplePropertyDescriptor, you can just override GetValue, SetValue and DisplayName. (GetValue and SetValue are abstract because the assumption is you might be dynamically adding new properties that don't have real underlying CLR properties. If you're just localizating a real property's name, you can just defer to the real property for these methods.)

    If you can't derive from TypeConverter.SimplePropertyDescriptor, derive directly from PropertyDescriptor instead. This requires a bit more work I think. It's been an age since I looked at this, but I think you end up having to override a load more methods. But the implementation should be straightforwards - basically you just need to obtain the real property descriptor and then defer to that for everything  but the DisplayName.

    lunes, 24 de julio de 2006 9:09
  • Ok

    But what am i supposed to do with controls like Button ?

    I cann't add them my TypeConverter.

    lunes, 24 de julio de 2006 13:59
  • No, but you can still use the ITypeDescriptorFilterService technique you're using now and completely replace their PropertyDescriptors with your own can't you?

    (I think you can still derive from TypeConverter.SimplePropertyDescriptor even if you aren't actually writing a TypeConverter. Irritatingly you still have to write a class derived from TypeConverter just so you can write a nested class derive from SimplePropertyDescriptor, but you don't actually have to do anything with that parent class. And if that doesn't work you can always just derive directly from SimplePropertyDescriptor.)

    lunes, 24 de julio de 2006 14:10
  • Hi,

    Here is what I eventually did

    foreach (object key in propertyKeys){

    if (properties[key].GetType().Name != "ExtendedPropertyDescriptor"){

    properties[key] =TypeDescriptor.CreateProperty(
    component.GetType(),
    (properties[key]
    as PropertyDescriptor),
    new Attribute[] { new DisplayNameAttribute(localizedKeys[key.ToString()]+"YY"), new DescriptionAttribute("Description l") });

    }
    else{

    properties[key] =TypeDescriptor.CreateProperty(
    (properties[key]
    as PropertyDescriptor).ComponentType,
    (properties[key]
    as PropertyDescriptor),
    new Attribute[] { new DisplayNameAttribute(localizedKeys[key.ToString()] + "XX"), new DescriptionAttribute("Description l") });
    }

    }

    From the reflection you can see (but not understand) why i did that

    [ReflectionPermission(SecurityAction.LinkDemand, Flags=ReflectionPermissionFlag.MemberAccess)]
    public static PropertyDescriptor CreateProperty(Type componentType, PropertyDescriptor oldPropertyDescriptor, params Attribute[] attributes)
    {
          if (componentType == oldPropertyDescriptor.ComponentType)
          {
                ExtenderProvidedPropertyAttribute attribute1 = (ExtenderProvidedPropertyAttribute) oldPropertyDescriptor.Attributes[typeof(ExtenderProvidedPropertyAttribute)];
                if (attribute1.ExtenderProperty is ReflectPropertyDescriptor)

    { return new ExtendedPropertyDescriptor(oldPropertyDescriptor, attributes);
                }
          }
          return new ReflectPropertyDescriptor(componentType, oldPropertyDescriptor, attributes);
    }

     

    martes, 25 de julio de 2006 8:49
  • Ian,
    I have a related question.  Do you know of a way to add properties, or change the name of properties of a class at runtime?  I want to write a multitenant application that needs to be polymorphic.  By that I mean there should be a way for one organization to define an entity, and add its own attributes to that entity.  That then becomes a class with customer properties.  Any ideas?
    Baloo
    martes, 07 de abril de 2009 15:40
  • You can't do this in C#.  You might want to consider using another language that isn't strongly typed.
    David Morton - http://blog.davemorton.net/
    martes, 07 de abril de 2009 16:14
  • Sorry my friend, Mr. IanG, but one CAN change attribute values at runtime.  It can be done quite easily as attributes are normal class objects.  See the following post for clarification: 

    http://stackoverflow.com/questions/51269/change-attributes-parameter-at-runtime

    However, as you and David M Morton have identified, adding/removing attribute meta-data at runtime is a whole other ballgame.

    • Editado Dennis M. Knippel viernes, 26 de noviembre de 2010 22:58 inserted hyperlink reference
    • Propuesto como respuesta Dennis M. Knippel viernes, 26 de noviembre de 2010 22:58
    viernes, 26 de noviembre de 2010 22:57