none
How To Add Attributes To Dynamic Properties Of DynamicObjects RRS feed

  • Question

  • Hi all,

    I tried the code block below, and propColl returns 0 count.
    Can I get some help?

     

                dynamic exO = new ExpandoObject();
                exO.FirstName = "John";
                PropertyDescriptorCollection propColl = TypeDescriptor.GetProperties(exO);
    

    The bottom line this:

    1). I need to create a type at runtime.
    2). I need to add properties and methods to the class that I created.
    3). I need to add attributes to the properties of the class, after they have been created.
    4). I need to invoke methods on the class.

    Can someone recomend the correct solution for that?

    Thanks in advance.


    sobo

    Monday, January 28, 2013 8:49 AM

Answers

  • Hi Sobo,

    Thank you for coming back to confirm this.

    >>Then I want to be able see and display these attributes, using

    Excuse me, I would like to repeat my above reply:

    TypeDescriptor can be dynamically extended by several services available through the target component's Site. The following table shows these services.

    Service name

    Description

    IExtenderProvider

    Enables another class, such as ToolTip, to provide extra properties to a component.

    ITypeDescriptorFilterService

    Enables another object to modify the standard metadata that is exposed by a component.

    ICustomTypeDescriptor

    Enables a class to completely and dynamically specify its own metadata, replacing the standard inspection mechanism ofTypeDescriptor.

    The ExpandoObject Class doesn't implement such interface, so TypeDescriptor doesn't work.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by sobo1 Friday, February 1, 2013 8:04 AM
    Friday, February 1, 2013 5:13 AM
    Moderator

All replies

  • Hi Sobo,

    Welcome to the MSDN Forum.

    Please take a look at this code project: http://www.codeproject.com/articles/110065/quickly-generate-and-use-dynamic-class And I have changed it a few:

            //1). I need to create a type at runtime.
            public static Type CreateMyNewType(string newTypeName, string propertyName, Type propertyType, Type baseClassType)
            {
                // create a dynamic assembly and module 
                AssemblyBuilder assemblyBldr =
                Thread.GetDomain().DefineDynamicAssembly(new AssemblyName("tmpAssembly"),
                AssemblyBuilderAccess.Run);
                ModuleBuilder moduleBldr = assemblyBldr.DefineDynamicModule("tmpModule");
    
                // create a new type builder
                TypeBuilder typeBldr = moduleBldr.DefineType
                (newTypeName, TypeAttributes.Public | TypeAttributes.Class, baseClassType);
    
                // Generate a private field for the property
                FieldBuilder fldBldr = typeBldr.DefineField
                ("_" + propertyName, propertyType, FieldAttributes.Private);
    
                //3). I need to add attributes to the properties of the class, after they have been created.
                // Generate a public property
                PropertyBuilder prptyBldr =
                            typeBldr.DefineProperty(propertyName,
                    PropertyAttributes.SpecialName, propertyType, new Type[] { propertyType });
                CustomAttributeBuilder attrBuilder = new CustomAttributeBuilder(typeof(MyCustomProperty).GetConstructor(new Type[] { typeof(String) }), new object[] { "abcdefg" });
                prptyBldr.SetCustomAttribute(attrBuilder);
                // The property set and property get methods need the following attributes:
                MethodAttributes GetSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig;
                // Define the "get" accessor method for newly created private field.
                MethodBuilder currGetPropMthdBldr =
                            typeBldr.DefineMethod("get_value", GetSetAttr, propertyType, null);
    
                // Intermediate Language stuff... as per Microsoft
                ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
                currGetIL.Emit(OpCodes.Ldarg_0);
                currGetIL.Emit(OpCodes.Ldfld, fldBldr);
                currGetIL.Emit(OpCodes.Ret);
    
                // Define the "set" accessor method for the newly created private field.
                MethodBuilder currSetPropMthdBldr = typeBldr.DefineMethod
                ("set_value", GetSetAttr, null, new Type[] { propertyType });
    
                // More Intermediate Language stuff...
                ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
                currSetIL.Emit(OpCodes.Ldarg_0);
                currSetIL.Emit(OpCodes.Ldarg_1);
                currSetIL.Emit(OpCodes.Stfld, fldBldr);
                currSetIL.Emit(OpCodes.Ret);
                // Assign the two methods created above to the PropertyBuilder's Set and Get
                prptyBldr.SetGetMethod(currGetPropMthdBldr);
                prptyBldr.SetSetMethod(currSetPropMthdBldr);
                // Generate (and deliver) my type
    
                //2). I need to add properties and methods to the class that I created.
                MethodBuilder MyOwnFunction = typeBldr.DefineMethod("MyOwnFunction", MethodAttributes.Public, CallingConventions.Standard, typeof(string), new Type[] { typeof(string) });
                ILGenerator currFunIL = MyOwnFunction.GetILGenerator();
                currFunIL.Emit(OpCodes.Ldarg_1);
                currFunIL.Emit(OpCodes.Ret);
    
                return typeBldr.CreateType();
            }

    And this code show you how to use this method: 

                Type newType = CreateMyNewType("NewType", "MyProperty", typeof(string), typeof(Object));
                PropertyInfo Mypropertyinfoc = newType.GetProperty("MyProperty");
    
                //Read the attribute
                object[] Myattributesc = Mypropertyinfoc.GetCustomAttributes(true);
                foreach (var a in Myattributesc)
                {
                    Console.WriteLine(a.GetType().FullName);
                }
    
                //4). I need to invoke methods on the class.
                object instanceNewType = Activator.CreateInstance(newType, null);
                string returnValue = (string)newType.InvokeMember("MyOwnFunction", BindingFlags.InvokeMethod, null, instanceNewType, new object[] { (object)"This is string from outside." });
                Console.WriteLine(returnValue);

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.


    Tuesday, January 29, 2013 8:33 AM
    Moderator
  • Thank you so much for the response and the solution you suggested; and it is an excellent solution.
    The only issue I would face with this approach is that after the type has been created,

    1).  I cannot add new properties to the type.
    2).  I cannot add new attributes to the type.
    3).  I cannot add new attributes to the properties of the type.

    Can I have another suggestion?

    Thanks



    sobo

    Tuesday, January 29, 2013 9:07 PM
  • Hi Sobo,

    Thank you for coming back and specific this issue.

    Here I would like to clarify this: Why would you like to add more properties after the type has been created?

    And How do you define the time "the type has been created", take the above code sample, when you call the method CreateMyNewType, it will return you a type. Do you mean you want to add one more property to this type in the button_click function (This is my understanding that the type has been created, is it correct?).

    If I am right, please try http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.aspx, here, I want to highlight the following:

    The .NET Framework provides two ways to access metadata on a type: the reflection API provided in the System.Reflection namespace, and the TypeDescriptor class. Reflection is a general mechanism available to all types because its foundation is established in the GetType method of the root Object class. The information it returns for a type is not extensible, in that it cannot be modified after compilation of the target type. For more information, see the topics in Reflection in the .NET Framework.

    And 

    In contrast, TypeDescriptor is an extensible inspection mechanism for components: those classes that implement the IComponent interface. Unlike reflection, it does not inspect for methods. TypeDescriptor can be dynamically extended by several services available through the target component's Site. The following table shows these services.

    Service name

    Description

    IExtenderProvider

    Enables another class, such as ToolTip, to provide extra properties to a component.

    ITypeDescriptorFilterService

    Enables another object to modify the standard metadata that is exposed by a component.

    ICustomTypeDescriptor

    Enables a class to completely and dynamically specify its own metadata, replacing the standard inspection mechanism ofTypeDescriptor.

    The extensibility provided by TypeDescriptor allows the design-time representation of a component to differ from its actual run-time representation, which makesTypeDescriptor useful for building design-time infrastructure.

    You need to implement the related interfaces firstly in the CreateTheNewType function.

    On the other hand, based on your description, your type has uncertain properties, so how about http://msdn.microsoft.com/en-us/library/system.dynamic.expandoobject.aspx 

                dynamic eo = new ExpandoObject();
                eo.WhateverNameJustWriteItHereproperty = "Whatever Name it is, Just Write It Here";

    I hope this will be clear.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, January 30, 2013 5:00 AM
    Moderator
  • Hi Mike,

    Thanks for the various links you provided.
    Please look at the code block below (which I presented in my original question).

    dynamic exO = new ExpandoObject();
    exO.FirstName = "John";
    PropertyDescriptorCollection propColl = TypeDescriptor.GetProperties(exO);

    The first 2 lines is similar to the sample you provided at the end of your reply.

    dynamic eo = new ExpandoObject();
    eo.WhateverNameJustWriteItHereproperty = "Whatever Name it is, Just Write It Here";
     

    The third line came from the first link you provided
    http://msdn.microsoft.com/en-us/library/system.componentmodel.typedescriptor.aspx

    This is my issue:
    PropertyDescriptorCollection
    propColl = TypeDescriptor.GetProperties(exO);
    Here, propColl returns 0 count.

    Since you are suggesting what I have already done,
    why did propColl return 0 count?
    What am I doing wrong?
    Here is where I need help.

    Thanks



    sobo

    Wednesday, January 30, 2013 7:40 AM
  • Hi Sobo,

    Please take a look at this code snippet:

    dynamic employee = new ExpandoObject();
    employee.Name = "John Smith";
    employee.Age = 33;
    
    foreach (var property in (IDictionary<String, Object>)employee)
    {
        Console.WriteLine(property.Key + ": " + property.Value);
    }

    You can see, the property Name doesn't look like the general properties in a normal class. This is why your expression returns 0.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Wednesday, January 30, 2013 10:18 AM
    Moderator
  • Hi Mike,

    Thank you so much. I was able to see the properties now.

    One more thing:

    Attribute displayName = new DisplayNameAttribute("enter displayName here");
    Attribute description = new DescriptionAttribute("enter description here");
    
    I want to use TypeDescriptor.AddAttributes(), to add these attributes to:

    employee, and also to
    employee.Name

    Then I want to be able see and display these attributes, using
    TypeDescriptor.GetAttributes()
    Thanks



    sobo

    Wednesday, January 30, 2013 12:14 PM
  • Hi Sobo,

    >>I was able to see the properties now. 

    Would you like to tell me how do you see the properties?

    Thank you.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, January 31, 2013 4:49 AM
    Moderator
  • Hi mike,

    I used your example by casting the object to IDictionary<String, Object>.
    I then used break points to inspect the variable values.

    Now, I just want to be able to do this:

    Attribute displayName = new DisplayNameAttribute("enter displayName here");
    Attribute description = new DescriptionAttribute("enter description here");
    I want to use TypeDescriptor.AddAttributes(), to add these attributes to:

    employee, and also to
    employee.Name

    Then I want to be able see and display these attributes, using
    TypeDescriptor.GetAttributes()

    Thanks


    sobo

    Thursday, January 31, 2013 9:00 PM
  • Hi Sobo,

    Thank you for coming back to confirm this.

    >>Then I want to be able see and display these attributes, using

    Excuse me, I would like to repeat my above reply:

    TypeDescriptor can be dynamically extended by several services available through the target component's Site. The following table shows these services.

    Service name

    Description

    IExtenderProvider

    Enables another class, such as ToolTip, to provide extra properties to a component.

    ITypeDescriptorFilterService

    Enables another object to modify the standard metadata that is exposed by a component.

    ICustomTypeDescriptor

    Enables a class to completely and dynamically specify its own metadata, replacing the standard inspection mechanism ofTypeDescriptor.

    The ExpandoObject Class doesn't implement such interface, so TypeDescriptor doesn't work.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by sobo1 Friday, February 1, 2013 8:04 AM
    Friday, February 1, 2013 5:13 AM
    Moderator
  • Okay, I'll look into those.

    Thanks.


    sobo

    Friday, February 1, 2013 8:03 AM
  • Hi sobo,

    You are welcome.

    Best regards,


    Mike Feng
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Friday, February 1, 2013 8:21 AM
    Moderator