Click here to monitor SSC
Vladimir Bodurov

Dynamically generating typed objects in .NET

14 July 2008

When you are binding Data to DataGrid in .NET, this has to be done at design-time. That's fine if you know what the form of the data is at design time: but what if you don't? Vlad Bodurov looks at some of the options and demonstrates an unusual dynamic technique that transforms IDictionary into a typed object.

How to bind DataGrid to a list of Hashtable objects
(or any IEnumerable of IDictionary)

Introduction

Are the traditional .NET languages, C# and Visual Basic, truly dynamic languages? Well, we all know the answer to that question: They are not. Ok, but if they can be used in the same way that we normally use dynamic languages then, perhaps, in a sense they are dynamic. So can we use those languages in some situations as if they were dynamic? My hope is that, after reading this article, you will agree that the answer to that question is a qualified "Yes".

I believe that the best way to illustrate this is to demonstrate how it can solve a common programming problem. The DataGrid and many of the controls, developed by Microsoft are designed in a way so to expect a list of typed objects as a data source. There are many good reasons for that; but, if we assume for a moment that there might be also a benefit of binding a DataGrid to a list of Hashtables without having to change the controls, wouldn't that be an example of the dynamic capabilities of .NET languages? If we can turn a list of key value pairs into a class with corresponding properties, then that would certainly be an example of crossing the barrier between dynamic data and static types: We have to be able to do that at run time, of course.

Why would you need to perform such a task? Well, you may need to do it if the number and type of the columns in your DataGrid is something that you can't predict at design time. This would be the case if, for example, you require that the columns in the grid will display items previously chosen by the user. There are several alternative programming strategies you could use to handle this, and the approach I'm about to describe is among them. I will discuss the other ways later in this article.

How to use it

You would expect that the way to pass dynamic data to the control should be very similar to a traditional dynamic language. Adding a key to Hashtable or IDictionary of (string, object) is just like adding a dynamic property to a dynamic object. In a dynamic language you would use something like this:

var myObject = new Object();

myObject["ID"] = 1;

myObject["Name"] = "Name";

In a .NET language you can do likewise, by using IDictionary. So our code, could look like that:

public IEnumerable<IDictionary> GenerateData()

{

    for(var i = 0; i < 10; i++)

    {

        // or you could use new Hashtable();

        var dict = new Dictionary<string, object>();

        dict["ID"] = Guid.NewGuid();

        dict["Name"] = "Name_" + i;

        dict["Index"] = i;

        dict["IsEven"] = (i % 2 == 0);

        yield return dict;

    }

}

or in Visual Basic (without the yield return statement)

Public Function GenerateData() As IEnumerable(Of IDictionary)

    Dim list As New List(Of IDictionary)()

    For i As Integer = 0 To 9

        ‘ or you could use new Hashtable()

        Dim dict As IDictionary = New Dictionary(Of String, Object)()

        dict("ID") = Guid.NewGuid()

        dict("Name") = "Name_" & i.ToString()

        dict("Index") = i

        dict("IsEven") = (i Mod 2 = 0)

        list.Add(dict)

    Next

    Return list

End Function

If we were allowed to bind IDictionary to a DataGrid we could just use this code:If we were allowed to bind IDictionary to a DataGrid we could just use this code:

public void BindGid(){

    MyGrid.DataSource = GenerateData();

    MyGrid.DataBind();

}

But you cannot bind a list of Hashtables or Dictionaries to DataGrid. If you attempt this, you will actually bind the properties of the collection object and not the key because value pairs are treated as object properties.

There is just one more thing we have to do in order to make that work. We have to define an extension method ToDataSource() of the IEnumerable of IDictionary. The method will transform the list of dictionaries into a list of typed objects with each key turned into object property of the corresponding type. So our binding method will have to be modified just as:

public void BindGid(){

    MyGrid.DataSource = GenerateData().ToDataSource();

    MyGrid.DataBind();

}

There is no such method defined by the .NET framework for IEnumerable of IDictionary so we have to define it, and much of this article describes how that works. You can also see the attached source of that extension method for both C# and Visual Basic.

Here we see one of the amazing aspects of .NET 3.5: we have the means to define a method for an interface as an extension method. This is also one dynamic feature in the framework because we don’t have to modify the definition of IEnumerable of T – something we would not be able to do anyway because this is as interface and yet we can make that method a part of the IEnumerable of IDictionary, by a simple inclusion of the extension method class into the current code. One more using statement and your interface is enriched with a new method. I have to stress here that overusing this feature may result in an abundance of unneeded methods but I think we can safely assume that anytime you have IEnumerable of IDictionary you can expect that it may be designed for transformation into a collection of typed objects.

The extension method will use the first IDictionary entry as a template for a newly created typed object. If the next IDictionary contains more properties then they will be ignored, if it contains fewer then the properties will be assigned with the default values. Each key of IDictionary must be alphanumeric and start with character – because it will be transformed into an object property. If it is not alphanumeric then an exception will be thrown. If the keys of IDictionary are not strings they will be transformed to strings by calling ToString() method. If you end up with a key collision because of different dictionary key objects resulting in the same string then an exception will be thrown.

It all may look like a lot of rules, but if you always use strings as keys for the IDictionary as you would in a dynamic language, and make sure that all IDictionary entries have the same keys with the same types, it will just work.

If you want column headers in the grid even if your collection contains no data, you would have to define columns of the grid and set the AutoGenerateColumns property to false.

Despite all the reflection, the code works fine in a middle trust environment of a typical shared hosting. You could also use the same code not only for traditional .NET applications but for Silverlight projects as well. In fact I came to the idea of using this extension method while working on a Silverlight application. In Silverlight 2.0 you have no Hashtables, so there you would use Dictionary of string and object. I find it quite exciting that, within the limited range of Silverlight framework, you can use so powerful data transformation techniques based on reflection. You don’t need to change anything to make it work in Silverlight. Just use the same code.

Static vs. Dynamic – system architecture concerns

I am sure some developers would be convinced that we shouldn’t use the technique I’ve described, because there is a reason for a DataGrid not to accept dynamic data. The argument, in a nutshell, is that the dynamic data does not enforce the data constraints and therefore opens a potential risk of errors.

This isn’t the place for the endless discussion of the merits of Static vs. Dynamic languages, but I cannot pass this topic without even mentioning it. I agree that in general we have to try to restrict the data to the constraints it should follow. This is especially true when we talk about data operations within the business layer, where the application business logic resides. However in the user interface layer, we can be a little bit more liberal if that will make us more agile and if it will help to implement UI changes easier, quicker and with less code. I think that the area of user interface data binding is a perfect place for a more dynamic approach.

It has to be said as well, that if you want to add a data verification code just between the method generating IEnumerable of IDictionary and the call to ToDataSource extension method you are free to do so. There is nothing that prevents you from doing that.

I personally believe that both dynamic and static code have their place in the architecture of one enterprise system. The business layer should be more static and the user interface can be more dynamic. But whatever is your opinion on this topic I believe you will agree with me that having one additional tool in your arsenal will not be a bad idea. And the approach I describe here is just another tool to pass dynamic data into a UI control that expects a collection of statically typed objects.

Alternative ways to pass dynamic data to a DataGrid

Internally the grid will check for the first item in the collection if it is ICustomTypeDescriptor. If it is not, then the properties of the object will be used for column binding. If it is, then the TypeDescriptor.GetProperties static method will transform that object into a collection of PropertyDescriptors. So defining your collection, as ICustomTypeDescriptor would be the classical way of passing dynamic data into a .NET control. This is because many of the .NET controls will check for the type to see if it is ICustomTypeDescriptor.

Here is a reference to Windows Forms code send to me by Lionel WindowsApplicationDataBinding.cs

The code here achieves the same goal as the code I propose; the transformation of IDictionary into a collection that can be bound, but it is based on PropertyDescriptors and ICustomTypeDescriptor interface. I find it to be a very impressive code and would certainly advise you to check it. It has some significant advantages – it does not use reflection and it does not have the restriction that the property has to start with letter.

But despite all the advantages this approach also has some drawbacks. Even though the Windows Forms DataGridView works fine with it, web forms DataGrid could not auto generate columns based on that code, so there you’d have to define the columns by yourself. But the biggest problem is that the code would not work in Silverlight because there is no PropertyDescriptor object defined by the Silverlight framework.

Another way to apply dynamic data to a DataGrid would be to generate DataSet out of Hashtable or XML or anything dynamic. If you choose this way you would have to do some more work to generate the DataSet.

You could also populate DataGrid with many other techniques that are not direct data binding but I will not discuss them, as they are not pure techniques of data binding – passing a collection of data and attaching the data elements to the UI.

All those methods should be considered as valid choices with their advantages and disadvantages.

The reason that I prefer the dynamic solution I’ve described is that it will work without any changes for Windows Forms, Web Forms and Silverlight. It can also be used for a wider range of goals beyond data binding because the objects generated are valid .NET types. The method I propose offers very clean and simple interface – a single extension method transforms “dynamic” object into typed one.

The disadvantage of this idea is in the fact that using reflection will have some performance implications – each binding will result in a separate new dynamic assembly. For a web project where you have thousands of users viewing the grid simultaneously you would rather choose the solution proposed by Lionel, but for a single Windows Forms user you should not expect to notice any performance drawbacks and the same is true for a Silverlight project. As a matter of fact Silverlight is probably the best candidate for that solution because the more traditional ways are not available there and yet this is a single client executing on the client machine and not on the server.

If solving this task is all you are interested in, then you can get the Visual Basic DataSourceCreator.vb or C# DataSourceCreator.cs source, where the ToDataSource extension method is defined and just use it in your code the way it was described above, but if you want to understand how it actually works, please read the next part of this article.

What if you use .NET 2.0 and not 3.5?

I chose to develop this idea using C# 3.0 feature of extension methods as I find this to be a very elegant way to extend the functionality of common interfaces very similar to the idea of extending a dynamic object by simply adding a new method.

However if you use .NET 2.0 you could still use my code. You would only have to change method definition

public static IEnumerable ToDataSource(this IEnumerable<IDictionary> list)

by removing this keyword to be as

 public static IEnumerable ToDataSource(IEnumerable<IDictionary> list) 

or in Visual Basic, change

 <Extension()> _

Public Function ToDataSource(ByVal list As IEnumerable(Of IDictionary)) As IEnumerable 

To remove the attribute Extension and have the method just as

 Public Function ToDataSource(ByVal list As IEnumerable(Of IDictionary)) As IEnumerable

Then in your code simply use it as a static method:

public void BindGid(){

    MyGrid.DataSource = DataSourceCreator.ToDataSource(GenerateData());

    MyGrid.DataBind();

}

How does it work?

Here is what happens inside the extension method. First of all I generate dynamic assembly and I call it “TempAssembly” plus the hash code of the IEnumerable collection. I then define the type of the object will be public class.

After that, I get the first IDictionary in the IEnumerable to be used as a template for the newly generated statically typed object. First I check with a regular expression that each key is alphanumeric and starts with letter so it can be transformed into property name. This is the regular expression I have used:

 

Regex PropertNameRegex = new Regex(@"^[A-Za-z]+[A-Za-z0-9_]*$", RegexOptions.Singleline);

 

If the key does not follow this constraint, then I throw an application exception. Then for each key I generate a property. In .NET on a lower level getter property is transformed to get_<PropertyName>() method and setter property is transformed to set_<PropertyName>(value) method. So I generate both setter and getter and the private field lying underneath. The private field starts as usual with an underscore character. I get the type for the properties and private field from the current value in the IDictionary. If the value is NULL then the property is of type object.

Here is how the code generating properties looks:

FieldBuilder fieldBuilder = typeBuilder.DefineField("_" + propertyName,

                                            propertyType,

                                            FieldAttributes.Private);

 

 

PropertyBuilder propertyBuilder =

    typeBuilder.DefineProperty(

        propertyName, PropertyAttributes.HasDefault, propertyType, null);

MethodBuilder getPropMthdBldr =

    typeBuilder.DefineMethod("get_" + propertyName,

        MethodAttributes.Public |

        MethodAttributes.SpecialName |

        MethodAttributes.HideBySig,

        propertyType, Type.EmptyTypes);

 

ILGenerator getIL = getPropMthdBldr.GetILGenerator();

 

getIL.Emit(OpCodes.Ldarg_0);

getIL.Emit(OpCodes.Ldfld, fieldBuilder);

getIL.Emit(OpCodes.Ret);

 

MethodBuilder setPropMthdBldr =

    typeBuilder.DefineMethod("set_" + propertyName,

      MethodAttributes.Public |

      MethodAttributes.SpecialName |

      MethodAttributes.HideBySig,

      null, new Type[] { propertyType });

 

ILGenerator setIL = setPropMthdBldr.GetILGenerator();

 

setIL.Emit(OpCodes.Ldarg_0);

setIL.Emit(OpCodes.Ldarg_1);

setIL.Emit(OpCodes.Stfld, fieldBuilder);

setIL.Emit(OpCodes.Ret);

 

propertyBuilder.SetGetMethod(getPropMthdBldr);

propertyBuilder.SetSetMethod(setPropMthdBldr);

After that, the process of object creation is completed, and you may think that we are done here – let’s just put it into an array of objects and this is all. Unfortunately this is not a good idea because UI controls may use the type of the collection for their internal functionality. Thus the Silverlight DataGrid has sorting functionality that is implemented based on a reflection of the bound collection. I assume that they do this because they want to be able to know what columns they have even if the collection is empty. But that means that we have to pass a collection not of general object type but of the dynamic type we have just generated. This is the way we do that:

var listType = typeof (List<>).MakeGenericType(new[] {objectType});

var listOfCustom = Activator.CreateInstance(listType);

As you can see, I generate a generic type List of our object type, then I instantiate it with the activator. After that I traverse each IDictionary DictionaryEntry, matching it with the corresponding property in order to set the value. Here we will get an exception if the type of the first IDictionary key is not the same as the type of the corresponding current IDictionary key.

You may ask here if all this reflection work will have significant performance implications, and I need to clarify that the length of the list of IDictionary objects will not have such performance implications because all the reflection work that I’ve described is being applied to the first IDictionary only. After that, the type is already created and everything is just as if you were binding a regular collection of predefined typed objects. In other words a slow down due to the reflection operations can be expected if you generate a huge number of columns / properties, but should not be expected because of a huge number of records. This is because all records except the first one are processed with a type defined in assembly that has already been loaded into the framework.

But still each binding will result in a creation of a dynamic assembly. This is not a problem for a single Windows or Silverlight application but might be a problem for multi-user server.

Summary

The solution that I’ve described here will be among your first choices for a Silverlight project where you have much more limited set of options. It is one of the many options in Windows Forms and can be applied in Web Forms, though it may not be the best choice in this case because each page visit results in a new assembly being generated on the server.

The ability to dynamically generate typed objects makes .NET a really powerful environment. We can retain the constraints of the statically typed objects and at the same time benefit from the agility of the dynamic data.

Data binding of the user interface is a critical point where the dynamic data has to be presented in a way that isn’t known at design time. Once we know how to transform IDictionary into a typed object we can just use Hashtables as if they were dynamic objects – and this is what has been demonstrated in this article. I hope that now you will agree with me in my conclusion that .NET languages C# and Visual Basic can be used just as regular dynamic language for data binding of user interface controls.

As always, the C# and VB code is downloadable from the speech-bubble at the top of the article.
Vladimir's blog on http://blog.bodurov.com is always well-worth reading.

Vladimir Bodurov

Author profile:

Vladimir Bodurov is Microsoft Certified Solution Developer for .NET with ten years in software development; he has worked for projects for Fortune 100 companies, and has been actively involved with open source project, like http://www.codeplex.com/FlajaxianFileUpload or http://www.codeplex.com/FlajaxianS3Upload. He is currently employed as a senior software developer at ThrillX Systems - Vancouver BC. He has a wide range of interests and experience with .NET, Silverlight, JavaScript, ActionScript for Flash and Flex and Transact SQL. His blog can be viewed at http://blog.bodurov.com

Search for other articles by Vladimir Bodurov

Rate this article:   Avg rating: from a total of 50 votes.


Poor

OK

Good

Great

Must read
Have Your Say
Do you have an opinion on this article? Then add your comment below:
You must be logged in to post to this forum

Click here to log in.


Subject: What is a dynamic language
Posted by: Raja B (not signed in)
Posted on: Wednesday, July 23, 2008 at 7:42 AM
Message: What is the author's definition of a dynamic language?

Subject: Re: What is a dynamic language
Posted by: vladibo (view profile)
Posted on: Wednesday, July 23, 2008 at 11:08 AM
Message: I agree with this definition: "dynamic language is a high level programming language whose behavior at runtime is similar to its behavior at compile type" taken from this http://www.shafqatahmed.com/2008/04/dynamic-languag.html blog entry.

Subject: Performance when using emitted assemblies
Posted by: Mark Taylor (not signed in)
Posted on: Thursday, July 24, 2008 at 3:52 AM
Message: I've done something similar to DataSourceCreator in the past albeit with XML as the data store rather than a dictionary. This would generate an assembly per schema which worked well but I found that there was a noticeable performance hit with each assembly that I generated. In the end, I put all the emitted code into a single assembly created at application startup. That's not applicable to your use case but it's something to be aware of.

Mark

Subject: Re:Performance when using emitted assemblies
Posted by: vladibo (view profile)
Posted on: Thursday, July 24, 2008 at 6:11 PM
Message: Thanks Mark,

This is a great idea for extending this tool by caching the created types and reusing them later. I will think about more generic way to implement this.

Vlad

Subject: Typo in regexp?
Posted by: Ulas (not signed in)
Posted on: Monday, July 28, 2008 at 4:25 AM
Message: Hi Vlad,

Great tutorial! It helped me quite a bit in dealing with not the general data grid but the free data grid from DevExpress which has a similar requirement for setting its datasource.

On a not so related note - is it just me or is there a little typo in your regexp? Do you not match 0 on purpose or is

^[A-Za-z]+[A-Za-z1-9_]*$

supposed to be

^[A-Za-z]+[A-Za-z0-9_]*$?

Thanks :)

Subject: Re:Typo in regexp?
Posted by: vladibo (view profile)
Posted on: Monday, July 28, 2008 at 10:42 AM
Message: Thanks Ulas,

This is a mistake, I'll ask it to be corrected.

Vlad

Subject: Re: Typo in Regexp
Posted by: Phil Factor (view profile)
Posted on: Tuesday, July 29, 2008 at 1:44 PM
Message: Vlad did. We fixed it. Thanks Ulas

Subject: Code update
Posted by: vladibo (view profile)
Posted on: Wednesday, January 21, 2009 at 3:43 PM
Message: The code was updated to include type caching. Please, go to my blog to get it from there:

http://blog.bodurov.com/blog/How-to-bind-Silverlight-DataGrid-from-IEnumerable-of-IDictionary

Subject: well
Posted by: lilop (view profile)
Posted on: Sunday, September 06, 2009 at 3:04 AM
Message: man,U are so good~

Subject: Phenomenal
Posted by: galgitron (view profile)
Posted on: Thursday, February 11, 2010 at 3:01 PM
Message: Wow dude, this is some sick voodoo magic you've produced here. Thank you so much for sharing. You've probably just saved my job. (If I could learn to keep my mouth shut until I know what I'm talking about, I'd probably be able to keep my job just as well, but sadly I'm already on the other side of that bridge)

Subject: How to handle null value
Posted by: Marvin (view profile)
Posted on: Wednesday, October 12, 2011 at 10:46 PM
Message: Very excellent work!
But I don't know how to handle null values.
for example, I have a DateTime column in database, and it's nullable, so if first line has data, its type will be System.DateTime, which will not allow nulls, and when read a row of null value, an error "can't convert null to DateTime" will be reported, how to handle such situation?

Thanks!

 

Top Rated

Acceptance Testing with FitNesse: Multiplicities and Comparisons
 FitNesse is one of the most popular tools for unit testing since it is designed with a Wiki-style... Read more...

Acceptance Testing with FitNesse: Symbols, Variables and Code-behind Styles
 Although FitNesse can be used as a generic automated testing tool for both applications and databases,... Read more...

Acceptance Testing with FitNesse: Documentation and Infrastructure
 FitNesse is a popular general-purpose wiki-based framework for writing acceptance tests for software... Read more...

TortoiseSVN and Subversion Cookbook Part 11: Subversion and Oracle
 It is only recently that the tools have existed to make source-control easy for database developers.... Read more...

TortoiseSVN and Subversion Cookbook Part 10: Extending the reach of Subversion
 Subversion provides a good way of source-controlling a database, but many operations are best done from... Read more...

Most Viewed

A Complete URL Rewriting Solution for ASP.NET 2.0
 Ever wondered whether it's possible to create neater URLS, free of bulky Query String parameters?... Read more...

Visual Studio Setup - projects and custom actions
 This article describes the kinds of custom actions that can be used in your Visual Studio setup project. Read more...

.NET Application Architecture: the Data Access Layer
 Find out how to design a robust data access layer for your .NET applications. Read more...

Calling Cross Domain Web Services in AJAX
 The latest craze for mashups involves making cross-domain calls to Web Services from APIs made publicly... Read more...

Web Parts in ASP.NET 2.0
 Most Web Parts implementations allow users to create a single portal page where they can personalize... Read more...

Why Join

Over 400,000 Microsoft professionals subscribe to the Simple-Talk technical journal. Join today, it's fast, simple, free and secure.