Ok, so we all know Reflecttion is many time less performant than "newing" a class instance, and in many cases this is just fine depending on the application requirements.
QUESTION: How can we create high performance .NET classes using a late binding (Reflection) strategy.
I have an existing requirement that demands class instances be created using reflection (CreateInstance), but performance is critical. In my situation I am creating instances for every incoming SMS Message in our application. During production this could easily be over a million per day.
I would like to hear and share some ideas on how to create .NET classes without directly referencing the classes in code, for example using Reflection. I was also thinking if there is a way to somehow cache a class Factory that can improve the "Creation" time
1 million a day is not a lot; I'd just use Activator.CreateInstance
(a quick test using Activator.CreatInstance(Type)
shows that on my lowly laptop it can create 1M objects from aType
in ~2s).
Thoughts on creating objects quickly:
- use generics and the
: new()
constraint (zero effort)
- use
DynamicMethod
and write the IL (not hard)
An implementation of the new
approach (without needing the : new()
constraint externally) is shown here: ObjectFactory.cs
.
For an IL example, see dapper-dot-net and il.Emit(OpCodes.Newobj, ...)
I don't think a million per day is too much for a simple reflection call. I believe you are over-optimizing but anyway, as you said, just create a factory class using a single Activator.CreateInstance
call and cache that one. Actual instances will be created using the CreateInstance()
method call on the returned object.
public interface IClassFactory {
IClass CreateInstance();
}
public interface IClass {
// your actual class interface.
}
public class DefaultClassFactory : IClassFactory {
public IClass CreateInstance() {
return new DefaultClass(); // the implementation class
}
}
Somewhere you'll have a static
field of type IClassFactory
which you'll set once with an instance of the DefaultClassFactory
or any other classes specified in config file or whatever.
Some thoughts:
- Keep one instance of each class around, once you find you need it. Then, instead of CreateInstance, Clone it.
- Once you've created the first instance, keep the Type of the instance around. then use Activator.CreateInstance(Type)
Cache the instance to clone or the Type in a Dictionary<string,Type>
or Dictionary<string,object>
.
As is usually the case, Jon Skeet is your friend here.
See his blog post Making reflection fly and exploring delegates
GREAT! The Class Factory approach seems to be the way to go here.
Using a combination of Assembly.CreateInstance(typeNameString)
on the first request, then cache Type
in the factory.
On subsequent calls use Activator.CreateInstance(type)
.
Using this approach it is 20% slower than using a native New operator. No big deal there!
Stats for creating of 10 million Employee
objects as follows:
Here is the sample code if anyone is interested:
private IEmployee CachedClassFactory()
{
if(_typeCache == null)
{
// This is a one time hit to load the type into the cache
string typeName = "ClassFactoryTest.Employee";
string assemblyName = "ClassFactoryTest";
Assembly assembly = Assembly.Load(assemblyName);
IEmployee employee = assembly.CreateInstance(typeName) as IEmployee;
_typeCache = employee.GetType();
}
IEmployee instance = Activator.CreateInstance(_typeCache) as IEmployee;
instance.FirstName = "Raiford";
instance.LastName = "Brookshire";
instance.Birthdate = DateTime.Now.AddYears(-35);
instance.Age = 35;
return instance;
}
Define and implement an interface instead of using reflection.