Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fast creation of objects instead of Activator.CreateInstance(type)

I'm trying to improve the performance of our application. We have a lot of Activator.CreateInstance calls that are causing some grief.

We instantiate a lot of classes based on an interface (ITabDocument) and after looking around I thought of using this code:

The code is no better (infact marginally slower) than using the Activator.CreateInstance code we had.

    public static Func<T> CreateInstance<T>(Type objType) where T : class, new()     {         var dynMethod = new DynamicMethod("DM$OBJ_FACTORY_" + objType.Name, objType, null, objType);         ILGenerator ilGen = dynMethod.GetILGenerator();         ilGen.Emit(OpCodes.Newobj, objType.GetConstructor(Type.EmptyTypes));         ilGen.Emit(OpCodes.Ret);         return (Func<T>)dynMethod.CreateDelegate(typeof(Func<T>));     } 

I'm wondering why this is, all I'm doing is:

ITabDocument document = CreateInstance<ITabDocument>(Type.GetType("[Company].Something")); 

Is there a better way of creating objects which would assist with the above? Its a little hard when you're not sure of the concrete type.

like image 799
Tiffany Townsend Avatar asked Jul 05 '11 11:07

Tiffany Townsend


People also ask

What is activator CreateInstance in C#?

The Activator. CreateInstance method creates an instance of a type defined in an assembly by invoking the constructor that best matches the specified arguments. If no arguments are specified then the constructor that takes no parameters, that is, the default constructor, is invoked.

What is activators dotnet?

Activator Class in . NET 4.0. Contains methods to create types of objects locally or remotely, or obtain references to existing remote objects.


1 Answers

I did some benchmarking between these (I would write down the bare minimum details):

public static T Instance() //~1800 ms {     return new T(); }  public static T Instance() //~1800 ms {     return new Activator.CreateInstance<T>(); }  public static readonly Func<T> Instance = () => new T(); //~1800 ms  public static readonly Func<T> Instance = () =>                                   Activator.CreateInstance<T>(); //~1800 ms  //works for types with no default constructor as well public static readonly Func<T> Instance = () =>                 (T)FormatterServices.GetUninitializedObject(typeof(T)); //~2000 ms   public static readonly Func<T> Instance =       Expression.Lambda<Func<T>>(Expression.New(typeof(T))).Compile();        //~50 ms for classes and ~100 ms for structs 

As CD says compiled expression is the fastest, and by a big margin. All the methods except (T)FormatterServices.GetUninitializedObject(typeof(T)) work only for types with default constructor.

And caching the compiled resultant delegate is trivial when you have a static class per generic type. Like:

public static class New<T> where T : new() {     public static readonly Func<T> Instance = Expression.Lambda<Func<T>>                                               (                                                Expression.New(typeof(T))                                               ).Compile(); } 

Note the new constraint. Call anything

MyType me = New<MyType>.Instance(); 

Except for the first time the class is being loaded in memory, the execution is going to be fastest.

To have a class that handles both types with default constructor and without, I took a hybrid approach, from here:

public static class New<T> {     public static readonly Func<T> Instance = Creator();      static Func<T> Creator()     {         Type t = typeof(T);         if (t == typeof(string))             return Expression.Lambda<Func<T>>(Expression.Constant(string.Empty)).Compile();          if (t.HasDefaultConstructor())             return Expression.Lambda<Func<T>>(Expression.New(t)).Compile();          return () => (T)FormatterServices.GetUninitializedObject(t);     } }  public static bool HasDefaultConstructor(this Type t) {     return t.IsValueType || t.GetConstructor(Type.EmptyTypes) != null; } 

Will handle value types too in an efficient manner.

Note that (T)FormatterServices.GetUninitializedObject(t) will fail for string. Hence special handling for string is in place to return empty string.

like image 71
nawfal Avatar answered Sep 21 '22 19:09

nawfal