views:

1051

answers:

6

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

+5  A: 

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.

Mehrdad Afshari
The only possible hiccup here is if the app is multithreaded you could have several different calls using the same instance, and end up with instances with mixed state. Perhaps returning a clone of the object if that's an issue?
Matt
Huh? Why? The Factory will always create a new instance and it's thread-safe itself as it has no internal state.
Mehrdad Afshari
@Matt he said a static factory, not the class itself being static. Factories are easy to make thread-safe.
Rex M
My bad, I read that as storying the underlying instance created by the factory in as static for easy return without creating new instances of the desired class
Matt
+7  A: 

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

Marc Gravell
+1 handy class.
RichardOD
new via generic constraint is not particularly quick...
flq
@Frank: only if your constructor is not particularly quick itself, in which case nothing will save you. `new()` via generic constraint results in an actual direct constructor invocation, so it does not get faster than that.
jerryjvl
@jerry - My Stopwatch tells me otherwise, sorry. From generic's new I consistently get a slightly worse performance (5-8 times slower). If you have a look with ildasm, the generic code calls Activator.CreateInstance<T>.
flq
@Frank - if construction time is **that** critical, then dynamic IL would probably be remaining option.
Marc Gravell
+1  A: 

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>.

John Saunders
+3  A: 

As is usually the case, Jon Skeet is your friend here. See his blog post Making reflection fly and exploring delegates

Dan Blanchard
A: 

Define and implement an interface instead of using reflection.

Thorarin
+1  A: 

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;  

     }
Raiford