How to customize the Reflection Metadata ?

By | August 29, 2013

If you dealt with Type API in .NET 4.5, you must have already found that there is a separate object that exists that subsets the Type object into a more lightweight object representation that provides metadata specific to a particular Type called here as TypeInfo. It is quite easy to deal with TypeInfo rather that the Type object actually.

Custom Reflection Context is another new addition to the Reflection API which allows to change or customize the TypeInfo based new Reflection API about your types. This can be extremely helpful when you are about to write libraries, and / or design components that can take help of the metadata components.  It provides virtualization over the TypeInfo object.

Let us take an example of a Modifier class whcih adds some properties and methods to the Student class defined as :

public class Student
{
public string StudentName { get; set; }
public int Class { get; set; }
public string GetReport()
{
// add logic to return a string
return string.Empty;
}
}

Here the student class contains two properties and a method. Let us add some more properties and methods using CustomReflectionContext class.

Remember : To use CustomReflectionContext, you need to add System.Reflection.Context.dll to your solution.

public class Modifier : CustomReflectionContext
{
private readonly Dictionary<string, object> _additioalProperties;

public Modifier(Dictionary<string, object> properties)
{
this._additioalProperties = properties;
}

protected override IEnumerable<PropertyInfo> AddProperties(Type type)
{
if (type == typeof(Student))
{
foreach (var p in this._additioalProperties)
{
Type newType = MapType(p.Value.GetType().GetTypeInfo());
yield return CreateProperty(newType, p.Key, o => _additioalProperties[p.Key], (o, v) => _additioalProperties[p.Key] = v);
}
}
else
base.AddProperties(type);
}
}

Here if you see minutely, we have actually declared a Dictionary object to hold some data. For any Type, when the corresponding metadata is retrieved, there is always a Context present which gets the data from some repository. Here you can think of the repository is present in AddProperties API. Now, here we have created a Dictionary of string and object where we are going to store some key value pair objects. The Key here represents the name of the property, while the Value represents the data.

When AddProperty is invoked for that particular ReflectionContext, it checks for the Type Student and use CreateProperty to add some more properties which we add dynamically to the Dictionary. For a property we need to pass the Get and Set method which is used to Get / Set property. We used Lambda to replace the calls.

Now to try this let us create an object of Student and add few properties to them

var properties = new Dictionary<string, object>()
{
{ "Section", "B"},
{"Roll", 20}
};
var context = new Modifier(properties);
var studentTypeInfo = typeof(Student).GetTypeInfo();

var customStudentTypeInfo = context.MapType(studentTypeInfo);

var s = new Student();
foreach (var property in customStudentTypeInfo.DeclaredProperties)
{
string propertyName = property.Name;
Console.WriteLine("{0} = {1}", propertyName, customStudentTypeInfo.GetProperty(propertyName).GetValue(s));
}

Console.ReadKey(true);

Here the studentTypeInfo has been mapped with the CustomReflectionContext and hence the AddProperty is called whenever the DeclaredProperties is called for. If you run this code, the Console will print Section and Roll in addition to the normal properties.

This comes very useful when you are creating a library of controls and you want some computed properties could be accessed by the user for flexibility.

I hope this post will come handy.

You can find more about hidden secrets of Memory Management in my book (NET 4.5 Expert Development Cookbook)

Thanks for reading.