10

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

Raiford
  • 159
  • 1
  • 7
  • waiting for C# 4.0 i suppose :) – Stan R. Jul 10 '09 at 22:00
  • 4
    How would C# 4.0 help, exactly? – Marc Gravell Jul 10 '09 at 22:06
  • Using Reflection to create an instance of an object is trivial in 99.9% of cases. Reflection in .NET is extremely fast - just write it and come back later if it's a problem. Guarantee it won't be. – Rex M Jul 10 '09 at 22:12
  • 4
    From some back-of-the-napkin calculations, for the main website I work with, we average well over 100 Activator.CreateInstance calls per second, all day every day. Not only is that not our performance bottleneck, it's not even on the list of measurable items to potentially improve. And that's just in the code we've written - not including usage in libraries we reference or the .NET framework. – Rex M Jul 10 '09 at 22:18
  • @Rex M; well... I'd go as far as to say that in many cases it is "fast enough" - but it can often be **much** slower than the IL approach. Which doesn't matter if it isn't a bottleneck, but does if it is ;-p – Marc Gravell Jul 10 '09 at 22:38
  • Narc, i was simply kidding around as C# 4.0 is introducing the new dynamic keyword..(yes i know thats not really what its suppose to be used for) – Stan R. Jul 10 '09 at 23:35
  • That sounds like a catch 22 statement to me! (:P) Reflection and high performance! Good reading though. – Andrew Siemer Jul 11 '09 at 00:00
  • Related: http://stackoverflow.com/questions/6582259/fast-creation-of-objects-instead-of-activator-createinstancetype – nawfal Jun 30 '16 at 22:20

6 Answers6

12

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

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • @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 Jul 10 '09 at 22:48
  • 2
    @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. – flq Jul 12 '09 at 11:55
  • @Frank - if construction time is **that** critical, then dynamic IL would probably be remaining option. – Marc Gravell Jul 12 '09 at 12:18
  • Looks like Google Code need the revision number now, so ObjectFactory is at http://code.google.com/p/protobuf-net/source/browse/trunk/protobuf-net/ObjectFactory.cs?r=277 – Chris S Sep 29 '11 at 12:24
  • @Chris ah, yes; that file no longer exists in the trunk – Marc Gravell Sep 29 '11 at 12:38
6

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
  • 414,610
  • 91
  • 852
  • 789
  • 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 Jul 10 '09 at 22:06
  • Huh? Why? The Factory will always create a new instance and it's thread-safe itself as it has no internal state. – Mehrdad Afshari Jul 10 '09 at 22:07
  • 1
    @Matt he said a static factory, not the class itself being static. Factories are easy to make thread-safe. – Rex M Jul 10 '09 at 22:10
  • 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 Jul 10 '09 at 22:11
5

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
  • 160,644
  • 26
  • 247
  • 397
  • Is cloning faster than creating an instance from a cached delegate? I Don't think it is, so would best be to cache the class contractor? would this be a delegate? if reflection was used to get the type and then to create an instance, would you get the contractor from the type or the instance. May some sample code could be added. My understanding is that caching the ctor of the types in a dictionary would be fastest. – Seabizkit Jun 15 '17 at 11:57
5

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

amurra
  • 15,221
  • 4
  • 70
  • 87
Dan Blanchard
  • 4,014
  • 1
  • 30
  • 26
1

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;    
}
nawfal
  • 70,104
  • 56
  • 326
  • 368
Raiford
  • 159
  • 1
  • 7
  • I think you can improve upon that using expression trees. See this for an [example](http://stackoverflow.com/questions/367577/why-does-the-c-sharp-compiler-emit-activator-createinstance-when-calling-new-in). – nawfal Jun 13 '13 at 04:05
  • not sure what you are showing here in terms of wording, how would a cached value be 20% slower? – Seabizkit Jun 15 '17 at 09:17
0

Define and implement an interface instead of using reflection.

Thorarin
  • 47,289
  • 11
  • 75
  • 111