About the author

Miron Abramson
Me
Software Engineer,
CTO at PixeliT
and .NET addicted for long time.
Open source projects:
MbCompression - Compression library

Recent comments

Authors

Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2014

Creative Commons License

Blog Flux Directory
Technology Blogs - Blog Top Sites

Create your own new Type and use it on run-time (C#)

It is not something you will use on daily bases. It doesn't have good performance. But one day, you will have to use it so it's good to know that it is possible. As you can understand from the title, I'm talking about creating a new type with fields and properties (it can also have methods), create instance/s from it and use it. It will not be 'type safe', of course, and you will be able to use it - read and set its values only with reflection. but, all the DataBindingControls (GridView, FormView etc...) are binding the data using reflection, so they will be happy to bind and use your new created objects from your own type you created on run-time.

Lets cut the crap and jump into the code:

Let's say you got an xml from a webservice. and you want to create an object from it. Something like that:

You receive an xml like this:

<root>
    <column name="Name">Miron</column>
    <column name="LastName">Abramson</column>
    <column name="Blog">www.blog.mironabramson.com</column>
</root> 

You want to make a 'match' type that looks like this:

public class MyType
{
    public string Name{ get; set; }
    public string LastName{ get; set; }
    public string Blog{ get; set; }
}

and than create an object from that type and fill it with your data. The prolem is that you don't know what will be the values of the xml attributes and fields. So you need to create the object on run-time:

private object CreateOurNewObject()
{
    string _xml = "<root>" +
        "<column name=\"Name\">Miron</column>" +
        "<column name=\"LastName\">Abramson</column>" +
        "<column name=\"Blog\">www.blog.mironabramson.com</column>" +
        "</root>";

    XmlDocument xmlDoc = new XmlDocument();
    xmlDoc.LoadXml(_xml);

    // create a dynamic assembly and module
    AssemblyName assemblyName = new AssemblyName();
    assemblyName.Name = "tmpAssembly";
    AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
    ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule");

    // create a new type builder
    TypeBuilder typeBuilder = module.DefineType("BindableRowCellCollection", TypeAttributes.Public | TypeAttributes.Class);

    // Loop over the attributes that will be used as the properties names in out new type
    foreach (XmlNode node in xmlDoc.SelectSingleNode("root").ChildNodes)
    {
        string propertyName = node.Attributes["name"].Value;

        // Generate a private field
        FieldBuilder field = typeBuilder.DefineField("_" + propertyName, typeof(string), FieldAttributes.Private);
        // Generate a public property
        PropertyBuilder property =
            typeBuilder.DefineProperty(propertyName,
                             PropertyAttributes.None,
                             typeof(string),
                             new Type[] { typeof(string) });

        // The property set and property get methods require a special set of attributes:

        MethodAttributes GetSetAttr =
            MethodAttributes.Public |
            MethodAttributes.HideBySig;

        // Define the "get" accessor method for current private field.
        MethodBuilder currGetPropMthdBldr =
            typeBuilder.DefineMethod("get_value",
                                       GetSetAttr,
                                       typeof(string),
                                       Type.EmptyTypes);

        // Intermediate Language stuff...
        ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
        currGetIL.Emit(OpCodes.Ldarg_0);
        currGetIL.Emit(OpCodes.Ldfld, field);
        currGetIL.Emit(OpCodes.Ret);

        // Define the "set" accessor method for current private field.
        MethodBuilder currSetPropMthdBldr =
            typeBuilder.DefineMethod("set_value",
                                       GetSetAttr,
                                       null,
                                       new Type[] { typeof(string) });

        // Again some Intermediate Language stuff...
        ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
        currSetIL.Emit(OpCodes.Ldarg_0);
        currSetIL.Emit(OpCodes.Ldarg_1);
        currSetIL.Emit(OpCodes.Stfld, field);
        currSetIL.Emit(OpCodes.Ret);

        // Last, we must map the two methods created above to our PropertyBuilder to
        // their corresponding behaviors, "get" and "set" respectively.
        property.SetGetMethod(currGetPropMthdBldr);
        property.SetSetMethod(currSetPropMthdBldr);
    }

    // Generate our type
    Type generetedType = typeBuilder.CreateType();

    // Now we have our type. Let's create an instance from it:
    object generetedObject = Activator.CreateInstance(generetedType);

    // Loop over all the generated properties, and assign the values from our XML:
    PropertyInfo[] properties = generetedType.GetProperties();

    int propertiesCounter = 0;

    // Loop over the values that we will assign to the properties
    foreach (XmlNode node in xmlDoc.SelectSingleNode("root").ChildNodes)
    {
        string value = node.InnerText;
        properties[propertiesCounter].SetValue(generetedObject, value, null);
        propertiesCounter++;
    }
  
    //Yoopy ! Return our new genereted object.
    return generetedObject;
}

Mazal Tov!!!

We create our type and instance from it on run-time !!!

In the file bellow, there is full working exmple of the code

 

MyTypeRunTime.zip (4.15 kb)

Currently rated 4.4 by 29 people

  • Currently 4.379311/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Posted by Miron on Monday, June 09, 2008 10:43 AM
Permalink | Comments (24) | Post RSSRSS comment feed

Related posts

Comments

Guan Tao's Blog cn

Sunday, June 29, 2008 8:07 PM

Guan Tao's Blog

Very good!

关涛 cn

Monday, July 07, 2008 7:21 AM

关涛

Good!

Jesper dk

Friday, August 08, 2008 9:23 PM

Jesper

Very good article.
I have a related problem. Let’s say that the first 3 columns are fixed and always present. Sometimes an extra column is added to the xml input. Because the first 3 columns are always present I want to implement a class with these three properties. The class is initialized with the xml-document and if it contains extra columns, variables and properties are created to reflect this in the class. How can I create properties on the fly from (this)? Hope you can help.

<root>
<column name="Name">Miron</column>
<column name="LastName">Abramson</column>
<column name="Blog">www.blog.mironabramson.com</column>
<column name="ExtraColumn">Some value</column>
</root>

public class MyType
{
public MyType(string xmlDoc) { … }
public string Name{ get; set; }
public string LastName{ get; set; }
public string Blog{ get; set; }
public string ExtraColumn{ get; set; } // dynamic property, created only if the xml-document have an “ExtraColumn”
}

Diego br

Thursday, October 23, 2008 8:29 AM

Diego

Very Good!

Miron il

Tuesday, November 04, 2008 1:06 PM

Miron

@Jasper,
Why do you need that property to be dynamic?
Why just have the extra property always, and leave it empty if there is no such node in the XML?
(Or maybe the property name is what important?)

Jugdesh in

Monday, February 02, 2009 6:16 PM

Jugdesh

this does not work with silverlight: at - Activator.CreateInstance(generetedType)
have any solution?

Miron il

Tuesday, February 03, 2009 11:05 PM

Miron

No idea about Silverlight.
It is not that the code behind is the same C# ??

Klinger ca

Monday, March 09, 2009 2:59 PM

Klinger

First of all, Thanks for sharing this Miron.

The code below compiles and run on my Silverlight dev environment. I am not sure what
the implications are regarding security in production environment.

It's just the original code with almost no changes.

Follow the code:
public void SomeMethodToLoadDataGrid(DataGrid dg, XElement doc, string elementName)
{
dg.ItemsSource = null;
dg.ItemsSource = CreateOurNewObject(doc, elementName);
}

private IList<object> CreateOurNewObject(XElement doc, string elementName)
{
var result = new List<object>();

// create a dynamic assembly and module
AssemblyName assemblyName = new AssemblyName();
assemblyName.Name = "tmpAssembly";
AssemblyBuilder assemblyBuilder = Thread.GetDomain().DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder module = assemblyBuilder.DefineDynamicModule("tmpModule"Wink;

// create a new type builder
TypeBuilder typeBuilder = module.DefineType("BindableRowCellCollection", TypeAttributes.Public | TypeAttributes.Class);

// Loop over the attributes that will be used as the properties names in out new type
var firstElement = doc.Elements(elementName).FirstOrDefault();

foreach (var node in firstElement.Attributes())
{
string propertyName = node.Name.LocalName;

// Generate a private field
FieldBuilder field = typeBuilder.DefineField("_" + propertyName, typeof(string), FieldAttributes.Private);
// Generate a public property
PropertyBuilder property =
typeBuilder.DefineProperty(propertyName,
PropertyAttributes.None,
typeof(string),
new Type[] { typeof(string) });

// The property set and property get methods require a special set of attributes:

MethodAttributes GetSetAttr =
MethodAttributes.Public |
MethodAttributes.HideBySig;

// Define the "get" accessor method for current private field.
MethodBuilder currGetPropMthdBldr =
typeBuilder.DefineMethod("get_value",
GetSetAttr,
typeof(string),
Type.EmptyTypes);

// Intermediate Language stuff...
ILGenerator currGetIL = currGetPropMthdBldr.GetILGenerator();
currGetIL.Emit(OpCodes.Ldarg_0);
currGetIL.Emit(OpCodes.Ldfld, field);
currGetIL.Emit(OpCodes.Ret);

// Define the "set" accessor method for current private field.
MethodBuilder currSetPropMthdBldr =
typeBuilder.DefineMethod("set_value",
GetSetAttr,
null,
new Type[] { typeof(string) });

// Again some Intermediate Language stuff...
ILGenerator currSetIL = currSetPropMthdBldr.GetILGenerator();
currSetIL.Emit(OpCodes.Ldarg_0);
currSetIL.Emit(OpCodes.Ldarg_1);
currSetIL.Emit(OpCodes.Stfld, field);
currSetIL.Emit(OpCodes.Ret);

// Last, we must map the two methods created above to our PropertyBuilder to
// their corresponding behaviors, "get" and "set" respectively.
property.SetGetMethod(currGetPropMthdBldr);
property.SetSetMethod(currSetPropMthdBldr);
}

// Generate our type
Type generetedType = typeBuilder.CreateType();

// Loop over all the generated properties, and assign the values from our XML:
PropertyInfo[] properties = generetedType.GetProperties();

// Loop over the values that we will assign to the properties
foreach (var element in doc.Elements(elementName))
{
object generatedObject = Activator.CreateInstance(generetedType);
int propertiesCounter = 0;
foreach (var att in element.Attributes())
{
string value = att.Value;
properties[propertiesCounter].SetValue(generatedObject, value, null);
propertiesCounter++;
}
result.Add(generatedObject);
}

//Yoopy ! Return our new genereted object.
return result;
}

Put Up Blog us

Wednesday, March 25, 2009 3:02 PM

Put Up Blog

I just want you to know that I am very thankful that I have read your post webmaster! Can you explain your theme further? So that I can fully understand it well. Well, some ideas of your post is familiar and just keep up the good work for making a nice post.Good luck.

le-vin dot info us

Tuesday, April 28, 2009 7:52 PM

le-vin dot info

this is very useful information, keep posting dude!

Ananya us

Monday, May 04, 2009 10:13 PM

Ananya

Klinger,
Thanks for the silverlight version of the code. I am able to bind dynamic data to my datagrid using this method.
Now I need to edit datagrid and save this value into an xml file. How I would be able to read modified value from datagrid?

Hoangtu vn

Sunday, June 14, 2009 12:49 PM

Hoangtu

Klinger,
Thanks for the silverlight version of the code. "Wink

Eric Neff us

Wednesday, June 17, 2009 1:15 PM

Eric Neff

What a great post. This hit the spot and then some! Thanks for posting this great example and sharing it with the world.

Ovidiu Tudorache ro

Friday, November 06, 2009 6:57 AM

Ovidiu Tudorache

Given a type, how could you extend it by adding properties?

blind eyes

Monday, November 09, 2009 6:03 AM

blind eyes

Nice work!!

Chris us

Friday, November 20, 2009 8:40 AM

Chris

Hi Miron,
thanks for the example. I'm having the same problem as Jesper. My class has some standard properties that are populated from a db. However we have some custom fields that users can define and we need to add these to an already existing class. We won't know the names of the properties(or the values) until runtime. (We then bind a list of the objects to a grid for display purposes). Any help/suggestions would be greatly appreciated.

kristoffer dk

Wednesday, November 25, 2009 8:32 PM

kristoffer

Thanks for the example. Do you also have an example where you get the values from the generated object?

Anakin Skywalker pt

Saturday, April 03, 2010 4:51 AM

Anakin Skywalker

Great article, it really helped me a lot! Thank you! Just one thing, can you explain the "IL stuff" plz?

psychics us

Wednesday, May 12, 2010 5:52 AM

psychics

This blog has some interesting info. I am really impressed with your efforts and really pleased to visit this post. Keep up the Good work going!! Thanks

Evgen

Thursday, May 13, 2010 3:18 PM

Evgen

It possible to add a new properties to existing class at runtime or not ?

Life Settlement us

Tuesday, May 25, 2010 2:50 AM

Life Settlement

You had given me a lot of new ideas .i am really thankfull to you and to your team for the support.

Thermal Control us

Tuesday, May 25, 2010 5:31 PM

Thermal Control

This tutorial is very helpful to all who need it, because you've explained perfectly and easy to understand. very pleased to be able to visit your site

WA Towing us

Tuesday, May 25, 2010 11:49 PM

WA Towing

One has to think through it before coming to a conclusion on about it,beautiful site I like the header.

gist us

Monday, May 31, 2010 7:42 AM

gist

Thank you for this blog. Thats all I can say. You most definitely have made this blog into something thats eye opening and important. You clearly know so much about the subject, youve covered so many bases. Great stuff from this part of the internet. Again, thank you for this blog.