Reputation: 159
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
Upvotes: 10
Views: 7497
Reputation: 4054
As is usually the case, Jon Skeet is your friend here. See his blog post Making reflection fly and exploring delegates
Upvotes: 5
Reputation: 159
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:
8 seconds using the new
operator
10 seconds using the Factory / Type / Cache approach.
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;
}
Upvotes: 1
Reputation: 1062745
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:
: new()
constraint (zero effort)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, ...)
Upvotes: 12
Reputation: 421988
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.
Upvotes: 6
Reputation: 161773
Some thoughts:
Cache the instance to clone or the Type in a Dictionary<string,Type>
or Dictionary<string,object>
.
Upvotes: 5