Instantiating a class using Reflection

Suppose I have three projects in my sln.

(1) xyz.a{Class Lib}{no reference added}
(2) yzx.b{Class Lib}{added the reference of xyz.a}
(3) zxy.c{Console App}{added the reference of xyz.a}

      

Now I need to instantiate the class located in yzx.b from xyz.a using reflection.

And also it should be regardless of the folder / directory name.

those. even if i changed the name of the yzx.b directory it should work.

Does anyone have any ideas?

+2


source to share


3 answers


First of all, Activator.CreateInstance () is the right way to go.

But there is a more interesting way:

  • 10 times faster
  • Don't trap exceptions in TargetInvocationException

Just create an expression that calls the constructor:

public static Func<object[], object> CreateConstructorDelegate(ConstructorInfo method)
{
        var args = Expression.Parameter(typeof(object[]), "args");

        var parameters = new List<Expression>();

        var methodParameters = method.GetParameters().ToList();
        for (var i = 0; i < methodParameters.Count; i++)
        {
            parameters.Add(Expression.Convert(
                               Expression.ArrayIndex(args, Expression.Constant(i)),
                               methodParameters[i].ParameterType));
        }

        var call = Expression.Convert(Expression.New(method, parameters), typeof(object));

        Expression body = call;

        var callExpression = Expression.Lambda<Func<object[], object>>(body, args);
        var result = callExpression.Compile();

        return result;
}

      

Performance test:



    public void activator()
    {
        var stopwatch = new Stopwatch();
        const int times = 10000000;

        stopwatch.Start();
        for (int i = 0; i < times; i++)
        {
            var v = Activator.CreateInstance(typeof (C));
        }
        stopwatch.Stop();

        Console.WriteLine(stopwatch.ElapsedMilliseconds + "ms with activator");

        var del = CreateConstructorDelegate(typeof(C).GetConstructor(new Type[0]));

        stopwatch = new Stopwatch();
        stopwatch.Start();

        var args = new object[0];

        for (int i = 0; i < times; i++)
        {
            var v = del(args);
        }

        stopwatch.Stop();

        Console.WriteLine(stopwatch.ElapsedMilliseconds + "ms with expression");
    }

      

Output:

1569ms with activator
134ms with expression

      

But:

  • C # 3.0 only
  • Complile () - long work

Just for the curious.

+10


source


You might want to check out the Activator.CreateInstance () methods . Just pass the assembly name to it and enter.



If you don't have a reference to the assembly at build time, you can reference it at runtime using Assembly.Load () .

+6


source


You can use Activator.CreateInstance to instantiate easily (this also does various caching of reflection information to speed up repeated calls), or Type.GetConstructor if you want to think about the constructor itself and also run it directly (via ConstructorInfo.Invoke )

+1


source







All Articles