Introduction
Reflection is one of the very powerful features in the Microsoft .NET framework. It provides a rich set of APIs under the namespace System.Reflection
for loading and handling assemblies and objects besides retrieving meta data information such as method information, property information, and attributes (annotations) dynamically at runtime.
Using Reflection indeed makes developers’ life easy, however it should be used to a minimum and in other words only when it is required; it impacts the performance to a great extent. There are different techniques that help using reflection in an efficient way.
Often times we use reflection without realizing the cost that it comes at. In this article we will look at some techniques that help in using reflection optimally.
Solution
In this article, we will discuss some of the techniques that can be used for either avoiding reflection completely or at least using it repetitively. In the remainder of the article we will look at some scenarios where reflection can be used effectively.
Scenario 1 – Dynamic invocation of a method
If the names of methods/members to be invoked on an object created at run time are known at the time of development then instead of using reflection for dynamically invoking them, use interfaces and call them statically.
Example of completely dynamic invocation
public void DynamicExecution()
{
Type objType = Type.GetType("DynamicExecution.Test.DynamicClass");
object obj = Activator.CreateInstance(objType);
MethodInfo mInfo = objType.GetMethod("AddNumbers",
new Type[] { typeof(int), typeof(int) });
mInfo.Invoke(obj, new object[] { 1, 5 });
PropertyInfo pInfo = objType.GetProperty("ID");
pInfo.SetValue(obj, "TEST_ID", null );
}
Disadvantages of using the above code are:
- Every dynamic call to a method or property is several times more expensive than a static call to the same method or property.
- Type safety of method parameters and property values is not checked during compile time and code can break at runtime if the parameters provided are not of the appropriate types.
- Code is lengthier than the optimized code and hence less maintainable.
Example of optimized code
Public void OptimizedDynamicExecution()
{
Type objType = Type.GetType("DynamicExecution.Test.DynamicClass");
IDynamicClass obj = Activator.CreateInstance(objType) as IDynamicClass;
if (null != obj)
{
int result = obj.AddNumbers(1, 5);
obj.ID = 10;
}
}
public interface IDynamicClass
{
int ID { get; set; }
int AddNumbers(int a, int b);
}
Benefits of using the above code are:
- Fast execution speed as the method is executed statically.
- Type safety achieved by making use of an interface.
- The same interface can be used at other places as appropriate.
- Shorter code for making method calls, etc.
Scenario 2 – Reading custom attributes from a class
Custom attributes (Annotations) are used to provide additional information about an assembly, a class, or a member of a class, so if a class is decorated with an attribute that is required every time you create an instance of that class then it is advisable to cache that value in a static variable so that reflection is used only for the first instance and can be avoided for subsequent instances.
Following is an example of an entity class:
[Table(Name="Employees")]
public class Employee : Entity
{
[PrimaryKey]
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public DateTime DOB { get; set; }
}
The above code is an example of an entity class Employee
which corresponds to a table in the database called “Employees”. If you look at it carefully, the property Id
is decorated with an attribute called PrimaryKey
. All the members including the class itself that are decorated with attributes have some special meaning which is required by the consumer of this class for processing each of its instances.
In order to retrieve this information, we have to apply reflection to read the attributes (annotations) from this class. It will be very expensive if it is repeated for every instance of this class. A better idea from a performance perspective would be to read it only for the first time and cache it for all subsequent instances.
Example of retrieving attributes information dynamically for every instance
public class Entity
{
public Entity()
{
Type curType = this.GetType();
object[] tableAttributes =
curType.GetCustomAttributes(typeof(TableAttribute), true);
if(null != tableAttributes && tableAttributes.Count() > 0)
{
}
}
}
Disadvantages of using the above code are
- Every time an object of this class is created, the attribute information is dynamically retrieved using reflection.
- Retrieving attribute information using reflection is a very expensive operation.
Following example demonstrates the concept of caching attribute information for achieving better performance:
public struct TableInfo
{
public string TableName;
public string PrimaryKey;
}
In this example code below, the constructor looks up a static dictionary object for the existence of table information using the current entity class’ type as the key. It will not be found for the first time and that’s when the attribute information will be retrieved using reflection and be kept in the collection for subsequent retrievals. This is how we save the cost of reflection.
public class Entity
{
private static Dictionary<Type, TableInfo> tableInfoList =
new Dictionary<Type, TableInfo>();
public Entity()
{
Type curType = this.GetType();
TableInfo curTableInfo;
if (!tableInfoList.TryGetValue(curType, out curTableInfo))
{
lock (this)
{
if (!tableInfoList.TryGetValue(curType, out curTableInfo))
{
object[] tableAttributes =
curType.GetCustomAttributes(typeof(TableAttribute), true);
if(null != tableAttributes && tableAttributes.Count() > 0)
{
curTableInfo = new TableInfo();
curTableInfo.TableName = ((TableAttribute) tableAttributes[0]).Name;
}
}
}
}
}
}
The example code above demonstrates how information can be retrieved from custom attributes once and be used for subsequent instances of the same class without having to run the reflection code every time.
Benefits of using this technique are:
- Reflection is applied only for the first time and a cached copy of the information is used for all subsequent times.
- The cost of reflection is minimized by using the caching technique.
Scenario 3 – Dependency Injection
Often times we need to inject dependencies in some pieces of code for decoupling the implementation logic of a particular functionality form the logic of its consumer so that the implementation can be provided by different providers at a later point of time. To handle this scenario we normally allow the user to configure the assembly and the class to be injected in the configuration file.
In such a scenario the application would require to load the assembly and dynamically create the instance of the dependency class using reflection every time it is needed; this operation is very expensive in terms of processing and would result in poor performance in case of heavy traffic to this part of the application.
Microsoft .NET light-weight code generation helps in resolving the problem of creating an instance of any object that is not known at design time. It provides a set of APIs under the namespace System.Reflection.Emit
for creating assemblies, classes, and methods etc., programmatically.
This technique can be used for reducing the overhead of creating objects using reflection every time by creating a dynamic method that would statically create the instance of the required class. This method’s delegate can then be cached in a dictionary for subsequent invocations.
Following example demonstrates this concept
public interface ISecurityProvider
{
bool ValidateUser(string userId, string password);
List<User> GetUsersList();
}
public interface DefaultSecurityProvider : ISecurityProvider
{
public bool ValidateUser(string userId, string password)
{
...
}
public List<User> GetUsersIist()
{
...
}
}
Example of completely dynamic invocation
private void CreateInstance()
{
Type classType =
Type.GetType("DefaultSecurityProvider, AssemblyName");
ISecurityProvider employeeInstance = Activator.CreateInstance(classType) as ISecurityProvider;
}
Disadvantages of using the above code are:
- Every time an instance of the dependency class is required, it will be created dynamically using reflection.
- Creating an object dynamically using reflection is a very expensive operation.
Following code demonstrates how the cost of reflection can be avoided:
private void CreateInstance()
{
Type classType =
Type.GetType("DefaultSecurityProvider, AssemblyName");
CreateInstanceDelegate createInstance = ObjectInstantiater(classType);
ISecurityProvider employeeInstance = createInstance() as ISecurityProvider;
}
Following delegate will be used for mapping the method dynamically created using Microsoft .NET light weight code generation technique
public delegate object CreateInstanceDelegate();
Following dictionary object will hold the delegates of the methods dynamically created for instantiating dependency class objects
private static Dictionary<Type, CreateInstanceDelegate>
_createInstanceDelegateList = new Dictionary<Type, CreateInstanceDelegate>();
Following function creates a method programmatically at run time for instantiating the objects of a given type.
public static CreateInstanceDelegate ObjectInstantiater(Type objectType)
{
CreateInstanceDelegate createInstanceDelegate;
if (!_createInstanceDelegateList.TryGetValue(objectType,
out createInstanceDelegate))
{
lock (objectType)
{
if (!_createInstanceDelegateList.TryGetValue(objectType,
out createInstanceDelegate))
{
DynamicMethod dynamicMethod =
new DynamicMethod("Create_" + objectType.Name,
objectType, new Type[0]);
ConstructorInfo ctor = objectType.GetConstructor(new Type[0]);
ILGenerator ilgen = dynamicMethod.GetILGenerator();
ilgen.Emit(OpCodes.Newobj, ctor);
ilgen.Emit(OpCodes.Ret);
createInstanceDelegate = (CreateInstanceDelegate)dynamicMethod
.CreateDelegate(typeof(CreateInstanceDelegate));
_createInstanceDelegateList[objectType] = createInstanceDelegate;
}
}
}
return createInstanceDelegate; }
The above code demonstrates how an object of any class can be created statically that is not known at design time and only recognized by its interface (contract).
In the above example we created a proxy method dynamically using APIs provided in the System.Reflection.Emit
namespace that creates the instance of the dependency class statically. Once this method is created we store it in a dictionary against the type of the dependency class as the key so that for all subsequent times we can pull this delegate from the dictionary and use it.
Benefits of using this technique are:
- The object of the dependency class is created statically using the
Object
instantiating method.
- This technique helps in avoiding reflection for object instantiation.
Scenario 4 - Setting the property values of an ORM entity dynamically
In all ORM frameworks, there are entity classes that correspond to tables in the database. The framework applies reflection for reading the values of the properties (columns) and setting the values of the properties (columns) from each instance of an entity class. This operation is very expensive and could reduce performance to a great extant. This can be handled by generating dynamic methods in the same way as it was demonstrated in scenario 3, however in this example we will achieve this using a new feature introduced in .NET Framework 3.5 called Expression Trees.
Following example demonstrates this concept
public class Employees
{
public int EmployeeID { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public DateTime BirthDate { get; set; }
}
List<Employees> empList = new List<Employees>();
Following code fills the list of employees from the data reader
List<Employees> empList = new List<Employees>();
using(SqlConnection con = new SqlConnection(@"Data Source=localhost\SQLEXPRESS;
Initial Catalog=Northwind;Integrated Security=True"))
{
SqlCommand cmd = new SqlCommand("Select * from employees");
cmd.Connection = con;
con.Open();
using (SqlDataReader reader = cmd.ExecuteReader())
{
empList = ReadList<Employees>(reader);
}
}
Example of setting the property values of an entity class dynamically using reflection
public List<T> ReadList<T>(SqlDataReader reader) where T : new()
{
var list = new List<T>();
while (reader.Read())
{
T entity = new T();
Type entityType = typeof(T);
foreach(var entityProperty in entityType.GetProperties())
{
entityProperty.SetValue(entity, reader[entityProperty.Name], null);
}
list.Add(entity);
}
return list;
}
Disadvantages of using the above code are:
- Setting the properties of an object using reflection is a very heavy operation.
- The developer has to take care of type safety while setting the value of the property
The following example demonstrates how values can be read from an object of SqlDataReader
and added to a list of an entity without having to write event static code as well as without applying reflection repeatedly.
Following function iterates through the data reader and populates a list of entities with relevant values
public List<T> ReadList<T>(SqlDataReader reader)
{
var list = new List<T>();
Func<SqlDataReader, T> readRow = GetReader<T>();
while (reader.Read())
{
list.Add(readRow(reader));
}
return list;
}
Following dictionary holds the delegate of the method generated dynamically for populating the data table values into the entity list
ConcurrentDictionary<Type, Delegate> ExpressionCache =
new ConcurrentDictionary<Type, Delegate>();
Following method creates a function programmatically using Expression tree feature of Microsoft .NET. The dynamically generated function is saved as a delegate in a dictionary for later retrieval
public Func<SqlDataReader, T> GetReader<T>()
{
Delegate resDelegate;
if (!ExpressionCache.TryGetValue(typeof(T), out resDelegate))
{
var indexerProperty = typeof(SqlDataReader).GetProperty("Item",
new[] { typeof(string) });
var statements = new List<Expression>();
ParameterExpression instanceParam = Expression.Variable(typeof(T));
ParameterExpression readerParam =
Expression.Parameter(typeof(SqlDataReader));
BinaryExpression createInstance = Expression.Assign(instanceParam,
Expression.New(typeof(T)));
statements.Add(createInstance);
foreach (var property in typeof(T).GetProperties())
{
MemberExpression getProperty =
Expression.Property(instanceParam, property);
IndexExpression readValue =
Expression.MakeIndex(readerParam, indexerProperty,
new[] { Expression.Constant(property.Name) });
BinaryExpression assignProperty = Expression.Assign(getProperty,
Expression.Convert(readValue, property.PropertyType));
statements.Add(assignProperty);
}
var returnStatement = instanceParam;
statements.Add(returnStatement);
var body = Expression.Block(instanceParam.Type,
new[] { instanceParam }, statements.ToArray());
var lambda =
Expression.Lambda<Func<SqlDataReader, T>>(body, readerParam);
resDelegate = lambda.Compile();
ExpressionCache[typeof(T)] = resDelegate;
}
return (Func<SqlDataReader, T>)resDelegate;
}
In the above code, we created a function dynamically using .NET expression tree feature that sets the values of an entity object after reading them from a SqlDataReader
object passed to it as a parameter. This method is compiled and cached in a dictionary so that it can be used for all subsequent times without having to recreate it.
Benefits of using this technique are:
- The developer is not required to write code for setting values of any entity.
- The expression tree created for the method can be serialized and transferred across process boundaries.
- It is easier to create an expression tree using the .NET APIs rather than writing the IL code.
Conclusion
We looked at four scenarios where the reflection technique was used in an inappropriate way that leads to poor performance and we also looked the techniques that can be used for improving the performance by either using an alternative to reflection or using the caching mechanism for avoiding the use of reflection repetitively.
Caching technique used in this article ensures that the information is retrieved using reflection only once and used multiple times.
Dynamic code generation using Light weight code generation technique and Expression Trees help in creating static proxy methods to avoid reflection in scenarios such as instantiating objects and setting/getting property values etc.
Further Reading