This article aims at quickly show you how to create and use a dynamic
type/class.
What do I call 'Dynamic Class'?
Occasionally I would like to add properties or methods to a class on the fly and
generate a new Type and be able to instantiate it and make the rest of the
application use it.
The new trend is to bind UI controls to classes that that contain data and
present the data effortlessly. WPF and Silverlight use such binding extensively
and by employing MVVM pattern the developer may create a very generic View (UI)
then programmatically manipulate the data (Model) then bind the two and present
the data ('effortlessly').
When do I use a 'Dynamic Class'?
Assume a query engine that in response to a query provides a table with 5
columns out of total of 20 existing columns - why 5? - Only because 20 column do
not fit on a page. For example: A database of musical CD's, which present the
Composer, Composition, Conductor, Orquestra and Soloist as the response-table.
The database also includes the make, serial number, recording year, price and
more.
The query itself returns all 20 columns (Model) but the code populates the
Data-to-Present class (ViewModel) with the only 5 columns, then I bind it to the
view and present it. The DataGrid- out of the box (WPF/Silverlight) - is
capable to digest the bound class and to spit out a grid that shows a column for
each public property in the bound class.
When the user queries for CD's that cost less than $20, it will be nice to show
an additional column for the price, same if the query is about recording year,
etc.
It will be nice if I can dynamically add properties to the Data-to-Present
class, so when I bind it to the data grid view it will automatically generate
the desired view for me – 'Dynamic Class'
How do I create Dynamic Class?
I actually create a dynamic type and instantiate it.
How do I create Dynamic Type?
The following code shows how to use Reflection in order to create a new type.
Few things are worth noting here:
-
I create a type that is derived from an existing type since it will make it
easier to refer to the new type later in the code.
- Even though I do not use the new type's name I have to supply one that is
unique.
- Verify the property doesn't exist already.
The following method takes 2 names (new-type's name, new-property's name) and 2
types (new-property's type, existing-base type) and does all the heavy lifting
needed in order to generate a (base) derived type with the requested property.
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);
// Generate a public property
PropertyBuilder prptyBldr =
typeBldr.DefineProperty(propertyName,
PropertyAttributes.None, propertyType,
new Type[] {
propertyType });
// 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 MS
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
return typeBldr.CreateType();
}
How do I use the Dynamic Class?
One of the benefits of having this new dynamic type derived from an existing
type is that I can use the existing type to hold the dynamic type or use the 'var'
keyword to define the variable.
But doing the above will not allow me to utilize the new property: the compiler
will complain since the compiler is unaware of the new type. So one thing I can
do is make the compiler more agreeable by declaring the variable that holds the
new type using the new keyword 'dynamic'. Doing so deferred the checking to run
time, at which point the new type has the requested property:
public static
Type CreateMyNewType(string
newTypeName, Dictionary dict, Type
baseClassType)
{
bool noNewProperties =
true;
// 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);

Mike GoldPosted Sep 20, 2010, 12:49 PM
thanks david, this is some hard-core coding. I'm wondering if there is any way to use the new dynamic keyword to somehow do the same thing? or does it not provide enough funcitonality?