39

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 (in fact 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? It's a little hard when you're not sure of the concrete type.

Amal K
  • 4,359
  • 2
  • 22
  • 44
Tiffany Townsend
  • 391
  • 1
  • 3
  • 5
  • 11
    How often are you *calling* `CreateInstance` - because the whole point of that is that you'd call `CreateInstance` once but then *remember* the factory delegate. If you're calling `CreateInstance` on each operation, then yes, it'll be slower... – Jon Skeet Jul 05 '11 at 12:00
  • 2
    Some design patterns may help you, like factory method, abstract factory and similar creational patterns. They allow you to late bind your objects. You could look here: http://oodesign.com – Nickolodeon Jul 05 '11 at 12:03
  • @Jon Skeet Thanks for replying, I'm calling it at least 20-30 times as we need to create that many tabbed documents at start and they're all different implementations of ITabbedDocument. – Tiffany Townsend Jul 05 '11 at 12:25
  • @Tiffany: But are they all different types? That's the important thing - you should only call that method once per type. – Jon Skeet Jul 05 '11 at 12:27
  • Oops, yes they are all different types. I've edited my example – Tiffany Townsend Jul 05 '11 at 12:41
  • possible duplicate of [Activator.CreateInstance Performance Alternative](http://stackoverflow.com/questions/4432026/activator-createinstance-performance-alternative) – nawfal Apr 23 '13 at 07:37
  • 1
    @JonSkeet could you explain to me what you mean by *remembering* the delegate? Which delegate here? Do you mean using `Delegate.CreateDelegate` on `Activator.CreateInstance` or just storing a `Func<>` which directly calls `CreateInstance`? – nawfal Jun 30 '16 at 08:05
  • @nawfal: I mean just store a reference to the value returned by `Delegate.CreateDelegate`, so that you don't need to create a new DynamicMethod each time. – Jon Skeet Jun 30 '16 at 08:14
  • @JonSkeet Ah I see, you were talking about DynamicMethod. I thought there was a way to make use of `Delegate.CreateDelegate` and `Activator.CreateInstance` together. – nawfal Jun 30 '16 at 11:04

6 Answers6

55

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.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
  • And how would this apply to creating an object whose type is only known at runtime as per the question? The question's use of generics is only for casting the returned object to a base class. In the example you have provided, the type of the instance returned is the same as the generic parameter and thus a normal constructor could be used (excepting the fact that it can also create an uninitialized object). – Richard Collette Jun 13 '13 at 16:35
  • @RichardCollette I agree its not directly answering the question but shows a way to have nice little helper class (the class is incomplete, hopefully I will update it a day). Nonetheless, it isn't too difficult to fine tune that to workable solution for OP (just use provided type instead of `typeof(T)`). – nawfal Jun 13 '13 at 18:30
  • 1
    The first one, the simple generic, new T()... It cannot be correct. This cannot be slower than the lambda version at the end. This should be as fast as a non-generic constructor, as generics are handled at compile time. Can you double check it? It's important, because it places doubt on all results in your otherwise excellent post! – Timo Feb 20 '17 at 12:21
  • @Timo depends on what you mean by "generics are handled at compile time". Some static checking is done, sure. But T will always have the runtime type. I think compiler should be smart enough to not rely on reflection in generic case but unfortunately it does. That's the whole point. You can also confirm this by inspecting IL. – nawfal Feb 20 '17 at 13:18
  • 1
    Read this blog https://codeblog.jonskeet.uk/2011/08/22/optimization-and-generics-part-1-the-new-constraint from Jon Skeet. And also the various benchmarks by users in comments all which verifies my results. Also note my comment in that blog which highlights how behaviour changed in Roslyn which is even slower now. – nawfal Feb 20 '17 at 13:18
  • @nawfal Wow, guess I spoke too soon! Thanks for the lesson *and* high-performance workaround. I salute you! – Timo Feb 22 '17 at 21:04
22

This might help: Don’t use Activator.CreateInstance or ConstructorInfo.Invoke, use compiled lambda expressions:

// Make a NewExpression that calls the ctor with the args we just created
NewExpression newExp = Expression.New(ctor, argsExp);                  

// Create a lambda with the New expression as body and our param object[] as arg
LambdaExpression lambda = Expression.Lambda(typeof(ObjectActivator), newExp, param);            


// Compile it
ObjectActivator compiled = (ObjectActivator)lambda.Compile();
CD..
  • 72,281
  • 25
  • 154
  • 163
  • Thanks, I saw this earlier but wasn't sure whether I can call it adhoc like I'd need. – Tiffany Townsend Jul 05 '11 at 12:27
  • 1
    Thanks for the link, it leads onto this blog http://rogeralsing.com/2008/02/28/linq-expressions-creating-objects/ which I've been reading and I think it may now be one of the best blogs I've ever seen. Thank you so much – RichK Jul 05 '11 at 15:18
  • 2
    Whilst this may theoretically answer the question, [it would be preferable](//meta.stackoverflow.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. Please edit your answer to correct this, then flag it as "in need of moderator intervention" and request un-deletion. – Matt Nov 01 '16 at 13:11
  • This is at least an order of magnitude faster, well worth it! – jjxtra Feb 22 '20 at 20:45
9

The problem is if your are going to call CreateInstance over and over again directly rather than saving the result somewhere and using that result over and over again, you should probably just go ahead and do you caching inside of it.

internal static class DelegateStore<T> {
     internal static IDictionary<string, Func<T>> Store = new ConcurrentDictionary<string,Func<T>>();
}

public static T CreateInstance<T>(Type objType) where T : class
{
    Func<T> returnFunc;
    if(!DelegateStore<T>.Store.TryGetValue(objType.FullName, out returnFunc)) {
        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);
        returnFunc = (Func<T>)dynMethod.CreateDelegate(typeof(Func<T>));
        DelegateStore<T>.Store[objType.FullName] = returnFunc;
    }
    return returnFunc();
}
Glenn Slayden
  • 17,543
  • 3
  • 114
  • 108
jbtule
  • 31,383
  • 12
  • 95
  • 128
  • 1
    You actually don't need a dictionary in your `DelegateStore` class at all because that generic class automatically gets a unique per-`T` instantiation already. This is true even though it is a `static` class. So all you need in `DelegateStore` is simply `internal static Func _cached_func;` As you have it, you're creating many dictionaries--a new one for every `T`--each containing just one single cached delegate. – Glenn Slayden Dec 13 '18 at 23:10
  • For anyone wanting to create value-types like this, the replacement for the Opcodes.Newobj line is: `LocalBuilder localVar = ilGen.DeclareLocal(objType);` `ilGen.Emit(OpCodes.Ldloca_S, localVar);` `ilGen.Emit(OpCodes.Initobj, objType);` `ilGenerator.Emit(OpCodes.Ldloc_S, localVar);` Thanks to [SharpLab](https://sharplab.io/) for helping me infer this! – ulatekh Nov 11 '20 at 21:29
7

UPDATED: Oct 13th, 2022
nawfal's answer benchmarked

Benchmarked in NET6.0, was just seeing how necessary this was still.

Added Activator.CreateInstance<T>(); test and struct tests.

Activator1 = new();
Activator2 = Activator.CreateInstance<T>();
Activator3 = New<T>.Instance();

TL;DR: Still recommended for simple classes. Don't use for structs.

using BenchmarkDotNet.Running;
using InstanceBenchmark;

//BenchmarkRunner.Run<ActivatorBenchmark<TestClass>>();
BenchmarkRunner.Run<ActivatorBenchmark<TestStruct>>();

public class TestClass
{
    public string Name { get; set; }
    public int Id { get; set; }
    public string Email { get; set; }
}

public struct TestStruct
{
    public string Name { get; set; }
    public int Id { get; set; }
    public string Email { get; set; }
}

[MemoryDiagnoser]
[SimpleJob(runtimeMoniker: RuntimeMoniker.Net60)]
[GenericTypeArguments(typeof(TestClass))]
[GenericTypeArguments(typeof(TestStruct))]
public class ActivatorBenchmark<T> where T : new()
{
    [Benchmark(Baseline = true)]
    [Arguments(1_000)]
    [Arguments(1_000_000)]
    [Arguments(100_000_000)]

    public void ActivatorTest1(int x)
    {
        for (int i = 0; i < x; i++)
        {
            var t = new T();
        }
    }

    [Benchmark]
    [Arguments(1_000)]
    [Arguments(1_000_000)]
    [Arguments(100_000_000)]

    public void ActivatorTest2(int x)
    {
        for (int i = 0; i < x; i++)
        {
            var t = Activator.CreateInstance<T>();
        }
    }

    [Benchmark]
    [Arguments(1_000)]
    [Arguments(1_000_000)]
    [Arguments(100_000_000)]
    public void ActivatorTest3(int x)
    {
        for (int i = 0; i < x; i++)
        {
            var t = New<T>.Instance();
        }
    }
}

public static class TestHelpers
{
    public static class New<T>
    {
        public static readonly Func<T> Instance = Creator();

        private 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;
    }
}

Class Results

// * Summary *

BenchmarkDotNet=v0.13.2, OS=Windows 11 (10.0.22000.1098/21H2)
Intel Core i9-10900KF CPU 3.70GHz, 1 CPU, 20 logical and 10 physical cores
.NET SDK=6.0.402
  [Host]   : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2
  .NET 6.0 : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2

Job=.NET 6.0  Runtime=.NET 6.0  

|         Method |         x |           Mean |         Error |        StdDev | Ratio | RatioSD |        Gen0 |     Allocated | Alloc Ratio |
|--------------- |---------- |---------------:|--------------:|--------------:|------:|--------:|------------:|--------------:|------------:|
| ActivatorTest1 |      1000 |       9.946 μs |     0.1927 μs |     0.2142 μs |  1.00 |    0.00 |      3.8147 |      39.06 KB |        1.00 |
| ActivatorTest2 |      1000 |       9.808 μs |     0.0721 μs |     0.0674 μs |  0.98 |    0.02 |      3.8147 |      39.06 KB |        1.00 |
| ActivatorTest3 |      1000 |       6.219 μs |     0.1199 μs |     0.1427 μs |  0.63 |    0.02 |      3.8223 |      39.06 KB |        1.00 |
|                |           |                |               |               |       |         |             |               |             |
| ActivatorTest1 |   1000000 |   9,834.625 μs |    31.8609 μs |    26.6053 μs |  1.00 |    0.00 |   3812.5000 |   39063.26 KB |        1.00 |
| ActivatorTest2 |   1000000 |  10,671.712 μs |    47.0675 μs |    44.0269 μs |  1.09 |    0.01 |   3812.5000 |   39063.26 KB |        1.00 |
| ActivatorTest3 |   1000000 |   6,295.779 μs |   121.9964 μs |   186.3014 μs |  0.65 |    0.03 |   3820.3125 |    39062.5 KB |        1.00 |
|                |           |                |               |               |       |         |             |               |             |
| ActivatorTest1 | 100000000 | 995,902.729 μs | 7,355.4492 μs | 6,520.4141 μs |  1.00 |    0.00 | 382000.0000 | 3906325.27 KB |        1.00 |
| ActivatorTest2 | 100000000 | 982,209.783 μs | 6,630.1000 μs | 5,176.3460 μs |  0.99 |    0.01 | 382000.0000 | 3906335.95 KB |        1.00 |
| ActivatorTest3 | 100000000 | 618,402.807 μs | 4,305.6817 μs | 4,027.5373 μs |  0.62 |    0.01 | 382000.0000 | 3906253.48 KB |        1.00 |

Struct Results

// * Summary *

BenchmarkDotNet=v0.13.2, OS=Windows 11 (10.0.22000.1098/21H2)
Intel Core i9-10900KF CPU 3.70GHz, 1 CPU, 20 logical and 10 physical cores
.NET SDK=6.0.402
  [Host]   : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2
  .NET 6.0 : .NET 6.0.10 (6.0.1022.47605), X64 RyuJIT AVX2

Job=.NET 6.0  Runtime=.NET 6.0

|         Method |         x |             Mean |         Error |        StdDev | Ratio | RatioSD | Allocated | Alloc Ratio |
|--------------- |---------- |-----------------:|--------------:|--------------:|------:|--------:|----------:|------------:|
| ActivatorTest1 |      1000 |         212.8 ns |       4.27 ns |       4.38 ns |  1.00 |    0.00 |         - |          NA |
| ActivatorTest2 |      1000 |         209.5 ns |       0.10 ns |       0.09 ns |  0.98 |    0.02 |         - |          NA |
| ActivatorTest3 |      1000 |       1,646.0 ns |       2.69 ns |       2.10 ns |  7.77 |    0.14 |         - |          NA |
|                |           |                  |               |               |       |         |           |             |
| ActivatorTest1 |   1000000 |     204,577.8 ns |     128.30 ns |     107.14 ns |  1.00 |    0.00 |         - |          NA |
| ActivatorTest2 |   1000000 |     204,569.4 ns |     116.38 ns |     108.86 ns |  1.00 |    0.00 |         - |          NA |
| ActivatorTest3 |   1000000 |   1,644,446.5 ns |  12,606.12 ns |   9,842.03 ns |  8.04 |    0.05 |       1 B |          NA |
|                |           |                  |               |               |       |         |           |             |
| ActivatorTest1 | 100000000 |  20,455,141.5 ns |  12,934.68 ns |  12,099.11 ns |  1.00 |    0.00 |      15 B |        1.00 |
| ActivatorTest2 | 100000000 |  20,460,807.6 ns |  25,571.37 ns |  19,964.44 ns |  1.00 |    0.00 |      15 B |        1.00 |
| ActivatorTest3 | 100000000 | 164,105,645.0 ns | 327,107.27 ns | 305,976.34 ns |  8.02 |    0.01 |     898 B |       59.87 |
HouseCat
  • 1,559
  • 20
  • 22
3

You're probably getting some overhead from the generation of the same code.

The ILGenerator dynamically creates code for the factory.

Create somekind of map or Dictionary of types you've already used, and keep the factory method created for that type.

Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
0

Generic method for constructing delegates, calling constructor directly. Automatically searches constructor in given type with signature of given delegate type and constructs delegate of that type. Code here:

/// <summary>
/// Reflective object construction helper.
/// All methods are thread safe.
/// </summary>
public static class Constructor
{
    /// <summary>
    /// Searches an instanceType constructor with delegateType-matching signature and constructs delegate of delegateType creating new instance of instanceType.
    /// Instance is casted to delegateTypes's return type. 
    /// Delegate's return type must be assignable from instanceType.
    /// </summary>
    /// <param name="delegateType">Type of delegate, with constructor-corresponding signature to be constructed.</param>
    /// <param name="instanceType">Type of instance to be constructed.</param>
    /// <returns>Delegate of delegateType wich constructs instance of instanceType by calling corresponding instanceType constructor.</returns>
    public static Delegate Compile(Type delegateType,Type instanceType)
    {
        if (!typeof(Delegate).IsAssignableFrom(delegateType))
        {
            throw new ArgumentException(String.Format("{0} is not a Delegate type.",delegateType.FullName),"delegateType");
        }
        var invoke = delegateType.GetMethod("Invoke");
        var parameterTypes = invoke.GetParameters().Select(pi => pi.ParameterType).ToArray();
        var resultType = invoke.ReturnType;
        if(!resultType.IsAssignableFrom(instanceType))
        {
            throw new ArgumentException(String.Format("Delegate's return type ({0}) is not assignable from {1}.",resultType.FullName,instanceType.FullName));
        }
        var ctor = instanceType.GetConstructor(
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic, null, parameterTypes, null);
        if(ctor == null)
        {
            throw new ArgumentException("Can't find constructor with delegate's signature","instanceType");
        }
        var parapeters = parameterTypes.Select(Expression.Parameter).ToArray();

        var newExpression = Expression.Lambda(delegateType,
            Expression.Convert(Expression.New(ctor, parapeters), resultType),
            parapeters);
        var @delegate = newExpression.Compile();
        return @delegate;
    }
    public static TDelegate Compile<TDelegate>(Type instanceType)
    {
        return (TDelegate) (object) Compile(typeof (TDelegate), instanceType);
    }
}

is part of Yappi project's sources. Using it you can construct delegate calling any constructor of given type, including constructor with parameters (except ref and out parameters).

Sample usage:

var newList = Constructor.Compile<Func<int, IList<String>>>(typeof (List<String>));
var list = newList(100);

After construction of delegate, store it somewhere in static dictionary or in static field of class with generic parameter. Don't construct new delegate each time. Use one delegate for constructing multiple instances of given type.

Kelqualyn
  • 489
  • 5
  • 7