
Have you been searching for a way to dynamically add properties to an object at runtime using C#?
If so, you may have come across how to do this using ExpandoObject
. However, after some further research, perhaps you’ve determined that it’s not what you are really looking for.
For example, you might be trying to data-bind a list of objects to a particular type of user interface control that does not support dynamic model binding. What you really need is an object instance containing dynamic properties which appear as if they were part of the object at the time of compilation.
In this article, I discuss an alternative approach for your situation by leveraging the .NET Reflection ‘Emit’ API.
Use cases
It’s quite common for an application to support custom properties for resources, to help cater to the unique needs of the end-user.
The canonical example for this is a product entity that is comprised of a standard set of properties, representing the attributes that apply to the majority of sectors. However, across the many possible industry ‘verticals’, a product will tend to look very different and may require an ‘Author’ property for bookshops or a ‘Size’ property for clothing outlets.
In this scenario, a user interface would be required to allow the additional properties for the product to be defined. For example, the Name and Type of the property and perhaps its Required status, amongst other things.
A further user interface would be required to allow the user to specify the value of each additional property and to associate the values with the product entity whenever it is saved.
There may be other use cases, but this is the most useful one that I have encountered.
ExpandoObject?
Before I introduce you to the alternative solution, let me remind you of how ExpandoObject
works.
If you haven’t come across ExpandoObject
before, below is a short description of it, taken from the Microsoft Docs.
Represents an object whose members can be dynamically added and removed at run time.
To create an ExpandoObject
simply ‘new it up’ and assign its return value to a dynamic
variable.
dynamic todo = new ExpandoObject();
Now that the ExpandoObject
has been created you can add properties to it, as follows.
todo.Id        = 1; todo.UserId    = 1; todo.Title     = "Buy Milk"; todo.Completed = false;
You can then proceed to add additional members anywhere in the codebase which has access to the todo
variable. This includes properties, event handlers and methods.
todo.Important = true; todo.Notes     = "2 for £2.20"; todo.ToString  = (Func<string>)(() => $"Title: {todo.Title}");
ExpandoObject
is very flexible and is great for ‘interoping’ with other languages and COM objects. However, creating a list of dynamic objects and trying to bind this to a control doesn’t tend to work so well. In many cases a lot of extra code is needed to make dynamic objects bindable, taking away from the usefulness of the feature. Furthermore, on some occasions, the binding will not work at all.
Underneath, ExpandoObject
implements the IDictionary<TKey,TValue>
interface, so it’s really just a Dictionary
class that holds a collection of keys and associated values.
Although ExpandoObject
is quite clever in that it implements the INotifyPropertyChanged
interface and can raise the PropertyChanged
event whenever a member has been added, deleted or modified; this doesn’t guarantee that it will work correctly with your preferred controls library.
The alternative solution I’ll show you in the following section allows new types of objects with real properties to be created in memory while your program is running.
Code Emission
The key to the solution is the concept of emitting code into a dynamic assembly that is created at runtime.
This is achieved with the Reflection ‘Emit’ API. This API is typically used in advanced scenarios, such as when developing script engines or compilers. We’ll use a small subset of the API to achieve the desired end result.
Note that the code extracts below are taken from a sample project I’ve created on GitHub. I have included a note below the most important code snippets to indicate where they can be found within the sample project. This will help you visualise how the pieces of the solution are put together before looking at the project as a whole.
Let’s look at the Framework classes we need to work with. The first two, are as follows.
private readonly AssemblyBuilder _assemblyBuilder; private readonly ModuleBuilder   _moduleBuilder;
Note that these are private readonly
fields located within a class named DynamicTypeFactory
.
AssemblyBuilder
provides us with a way to create dynamic assemblies on the fly while our program is running.
All .NET assemblies are made up of at least one module. ModuleBuilder
allows us to create one or more modules within dynamic assemblies.
We only need one assembly and module at a time, which we can create using the following code.
var uniqueIdentifier = Guid.NewGuid().ToString(); var assemblyName     = new AssemblyName(uniqueIdentifier); _assemblyBuilder = AssemblyBuilder.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndCollect); _moduleBuilder   = _assemblyBuilder.DefineDynamicModule(uniqueIdentifier);
Note that this code is located within the constructor of DynamicTypeFactory
.
We make sure that the assembly and module have a unique name by using a Guid
as the name for both entities.
Notice that I’ve specified the RunAndCollect
access mode for the assembly. This means that the dynamic assembly will be automatically unloaded and its memory will be reclaimed whenever it’s no longer accessible.
There is one more Framework class that we need to be aware of.
private TypeBuilder _typeBuilder;
Note that this is a private field located within DynamicTypeFactory
.
TypeBuilder
gives us the ability to define new members and add them to an existing Type
.
We use the ModuleBuilder
instance to define a new Type
for the TypeBuilder
instance to work with.
_typeBuilder = _moduleBuilder.DefineType(parentType.Name + Guid.NewGuid().ToString(), TypeAttributes.Public); _typeBuilder.SetParent(parentType);
Note that this code is located within a public method named CreateNewTypeWithDynamicProperties
in DynamicTypeFactory
. The parentType
variable is an instance of theType
of the object we wish to extend.
We make sure that the new Type
we are creating has a unique name using a Guid
and set a parent to use as a starting point.
You may have noticed the hierarchical nature of the Framework classes. TypeBuilder
depends on ModuleBuilder
which in turn depends on AssemblyBuilder
.
Now for the complicated bit… This is all of the code which is needed to add a new property to an existing Type
.
Type   propertyType = typeof(string); string propertyName = "Notes"; string fieldName    = $"_{propertyName.ToCamelCase()}"; FieldBuilder fieldBuilder = _typeBuilder.DefineField(fieldName, propertyType, FieldAttributes.Private); // The property set and get methods require a special set of attributes. MethodAttributes getSetAttributes = MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig; // Define the 'get' accessor method. MethodBuilder getMethodBuilder     = _typeBuilder.DefineMethod($"get_{propertyName}", getSetAttributes, propertyType, Type.EmptyTypes); ILGenerator   propertyGetGenerator = getMethodBuilder.GetILGenerator(); propertyGetGenerator.Emit(OpCodes.Ldarg_0); propertyGetGenerator.Emit(OpCodes.Ldfld, fieldBuilder); propertyGetGenerator.Emit(OpCodes.Ret); // Define the 'set' accessor method. MethodBuilder setMethodBuilder     = _typeBuilder.DefineMethod($"set_{propertyName}", getSetAttributes, null, new Type[] { propertyType }); ILGenerator   propertySetGenerator = setMethodBuilder.GetILGenerator(); propertySetGenerator.Emit(OpCodes.Ldarg_0); propertySetGenerator.Emit(OpCodes.Ldarg_1); propertySetGenerator.Emit(OpCodes.Stfld, fieldBuilder); propertySetGenerator.Emit(OpCodes.Ret); // Lastly, we must map the two methods created above to a PropertyBuilder and their corresponding behaviors, 'get' and 'set' respectively. PropertyBuilder propertyBuilder = _typeBuilder.DefineProperty(propertyName, PropertyAttributes.HasDefault, propertyType, null); propertyBuilder.SetGetMethod(getMethodBuilder); propertyBuilder.SetSetMethod(setMethodBuilder); // Add a 'DisplayName' attribute. var attributeType    = typeof(DisplayNameAttribute); var attributeBuilder = new CustomAttributeBuilder(     attributeType.GetConstructor(new Type[] { typeof(string) }), // Constructor selection.     new object[] { "Task Notes" }, // Constructor arguments.     new PropertyInfo[] { }, // Properties to assign to.                        new object[] { } // Values for property assignment.     ); propertyBuilder.SetCustomAttribute(attributeBuilder);
Note that this code is located within a private method named AddDynamicPropertyToType
within DynamicTypeFactory
. I have hard-coded the values of propertyType
and propertyName
variables in the code extract for the sake of clarity. The ToCamelCase
method is a custom extension method.
The code above creates a new string
property called Notes
with a backing field called _notes
.
The backing field is created using an instance of FieldBuilder
.
Instances of MethodBuilder
are used to create the property get and set methods.
Instances of IlGetGenerator
do the magic of emitting IL (Intermediate Language) code into the dynamic assembly.
The PropertyBuilder
instance is used to associate the get and set property methods with the actual property.
Lastly, as a bonus, we add a DisplayNameAttribute
to the property which has been generated. This can be very useful in a UI context e.g. for grid column header captions.
After all that we can now create the new Type
 using the following code.
Type extendedType = _typeBuilder.CreateType();
To create an instance of the type we can use standard Reflection code, as follows.
var extendedObject = Activator.CreateInstance(extendedType);
Now that we have an instance of the new type we can populate its members, again using Reflection.
extendedType.GetProperty($"{nameof(Todo.Title)}")             .SetValue(extendedObject, "Buy milk", null);
Lastly, we can now create a collection and add our extended objects to it. When the collection of objects is assigned to a control as a data-source the objects will behave just like statically compiled objects!
Using the Factory
In the sample project, I demonstrate how to use the DynamicTypeFactory
to create new object Types with just a couple of statements, as per the code below.
// Create a new Type based on a 'Todo' with additional dynamic properties. var factory      = new DynamicTypeFactory(); var extendedType = factory.CreateNewTypeWithDynamicProperties(typeof(Todo), dynamicProperties); // Create an instance of the new extended Type. var extendedObject = Activator.CreateInstance(extendedType);
The same instance of the Factory can be used to construct multiple new Types with different base Types and/or a different set of dynamic properties.
Extending the solution
To make the solution practical, a way of storing the definition of the additional properties will be needed.
I hinted at this in the Use cases section where I talked about being able to define the properties and also configure and save the values for them.
Below is an example of what the definition of a dynamic property could look like as a class in code.
/// <summary> /// Represents the definition of a dynamic property which can be added to an object at runtime. /// </summary> public class DynamicProperty {     /// <summary>     /// The Name of the property.     /// </summary>     public string PropertyName { get; set; }     /// <summary>     /// The Display Name of the property for the end-user.     /// </summary>     public string DisplayName { get; set; }     /// <summary>     /// The Name of the underlying System Type of the property.     /// </summary>     public string SystemTypeName { get; set; }     /// <summary>     /// The underlying System Type of the property.     /// </summary>     [JsonIgnore]     public Type SystemType => Type.GetType(SystemTypeName); }
A structure like this could either be serialised to JSON, mapped to a database table or stored in a document database in some other format.
The associated values could be stored in a similar way, with the appropriate property names and types, along with an ID that links the values back to the parent object.
I have demonstrated a rudimentary way of achieving something like this in my sample Dynamic Properties GitHub Repository. The project also includes all of the code from this article along with the relevant models, extension methods and content files.
Combining the above with user interfaces to define and save the properties definitions and values would provide a slick solution that is very extensible.
I hope that you’ll find a suitable use case for what I’ve covered in this article.
Regardless, I’m sure you’ll agree that being able to generate IL on the fly is very cool!
Comments
Randy
Hello Jonathan,
Thanks for this post, very intriguing, good work figuring all that out. I implemented your methods in my code and mostly it worked: I was able to bind an “emitted” property to a TextBox my UI in WPF. That’s great!
However, I did not succeed when I tried to use that same property in a WPF DataGrid. To wit, I have a DataGrid with AutoGenerateColumns=”True”, when I ran the code, my new property was not displayed in the grid. There must be something different about how DataGrids identify properties to autogenerate, compared to binding to TextBoxes.
I wonder if you have been able to bind a list of entities, with newly created (“emitted”) properties, to a DataGrid with AutoGenerateColumns?
June 10, 2021Jonathan Crozier
Hey Randy,
Thank you very much for your comment.
I’ve tested out the solution with a WPF DataGrid and have found that it works just fine when using the ‘AutoGenerateColumns’ feature. If you’re able to share a link to your code (via my contact form) I’m happy to take a look at it for you 🙂
June 13, 2021Peter
Hi Randy,
many thanks for the work you have done to figure this out. Do you know how I can implement INotifyPropertyChanged interface for the dynamically generated properties?
Many Thanks, Peter
August 1, 2021Jonathan Crozier
Hi Peter,
I haven’t yet come across the need to implement the
INotifyPropertyChanged
interface for dynamically generated properties. However, the following link looks like it might be useful to you?https://pieterderycke.wordpress.com/2011/07/08/dynamically-adding-raisepropertychanged-to-mvvm-light-viewmodels-using-reflection-emit/
August 1, 2021Carlos
I’ve tried to use this on EntityFramework.Core to generate DbSets automatically but without success, but is an amazing work! congrats
December 28, 2024Jonathan Crozier
Hi Carlos, thanks very much for your feedback! 😊 If there’s anything about your scenario that I can help with, please let me know!
December 30, 2024