How to create an activator.createinstance() with expressions?

479 views Asked by At

The method activator.CreateInstance() is known to be slow. Direct calling var X = new Class() is the quickest. But Expression.New() compiled is also very quick.

But I don't know how to let it work with a variable number of params in the constructor.

So my question is: how should I create a func<Type, object[], object> with expressions to create an instance, where the object array contains the parameters for the constructor.

The end goal is to do this:

var a = Creator(typeof(ClassA),new[]{1,2}); //ClassA has 2 params
var b = Creator(typeof(ClassB),new[]{"some text"}); //ClassB has only 1 param

I have read in the Expression.New() there is a possibility to have multiple params.

1

There are 1 answers

3
dododo On BEST ANSWER

The above question in a comment can bring some light too, but regarding Expression.New and parameters:

    public class Dummy
    {
        public Dummy(int a) => A = a;
        public int A;
    }

    static void Main(string[] args)
    {
        var classTypeInfo = typeof(Dummy).GetTypeInfo();
        var constructorInfo = classTypeInfo.GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly).First();
        var parameters = constructorInfo.GetParameters().Select(p => Expression.Parameter(p.ParameterType, p.Name)).ToArray();
        var body = Expression.New(constructorInfo, parameters);
        var lambda = Expression.Lambda(body, parameters);
        var @delegate = lambda.Compile();
        // case 1
        var func = (Func<int, Dummy>)@delegate;
        var value = func(10);

        // case 2
        var value = (Dummy)@delegate.DynamicInvoke(10);

        Console.WriteLine(value.A);  // 10
    }