实例化一个类使用反射 [英] Instantiating a class using Reflection

查看:137
本文介绍了实例化一个类使用反射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设我有三个项目在我的SLN。

 (1)xyz.a {类库} {没有提及加}
(2)yzx.b {类库} {添加xyz.a参考}
(3)zxy.c {控制台应用程序} {添加xyz.a参考}
 

现在,我需要创建一个类居住在yzx.b从内部xyz.a使用反射实例。

和也本应是独立的文件夹/目录名。

即。甚至如果我改变yzx.b的目录的名称,它应该工作。

没有人有任何想法?

解决方案

首先,Activator.CreateInstance()是一个正确的方式。

但是,有一个更有趣的方式是:

  • 10倍
  • 请不要换行异常 TargetInvocationException

只要创建EX pression调用构造函数:

 公共静态函数功能:LT;反对[],对象> CreateConstructorDelegate(ConstructorInfo法)
{
        变参=前pression.Parameter(typeof运算(对象[]),ARGS);

        VAR参数=新的名单,其中,前pression>();

        VAR methodParameters = method.GetParameters()了ToList()。
        对于(VAR I = 0; I< methodParameters.Count;我++)
        {
            parameters.Add(前pression.Convert(
                               防爆pression.ArrayIndex(参数,防爆pression.Constant(I)),
                               methodParameters [I] .ParameterType));
        }

        VAR通话=前pression.Convert(出pression.New(方法参数)的typeof(对象));

        防爆pression体=调用;

        VAR callEx pression =前pression.Lambda< Func键<对象[],对象>>(机身,参数);
        VAR的结果= callEx pression.Compile();

        返回结果;
}
 

性能测试:

 公共无效激活剂()
    {
        VAR秒表=新的秒表();
        const int的时间=千万;

        stopwatch.Start();
        的for(int i = 0; I<次;我++)
        {
            变种V = Activator.CreateInstance(typeof运算(C));
        }
        stopwatch.Stop();

        Console.WriteLine(stopwatch.ElapsedMilliseconds +毫秒激活剂);

        VAR德尔= CreateConstructorDelegate(typeof运算(C).GetConstructor(新类型[0]));

        秒表=新的秒表();
        stopwatch.Start();

        变参=新对象[0]​​;

        的for(int i = 0; I<次;我++)
        {
            变种V =德尔(参数);
        }

        stopwatch.Stop();

        Console.WriteLine(stopwatch.ElapsedMilliseconds +毫秒EX pression);
    }
 

输出:

  1569ms与激活
与前pression 134ms
 

不过:<​​/ P>

  • 在C#3.0中,只有
  • Complile()是长时间运行的操作

只是为了好奇。

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 create the instance of a class residing in yzx.b from within xyz.a using reflection.

And also this should be independent of the folder/directory-names.

I.e. even If I change the name of the directory of yzx.b, it should work.

Does anyone have any idea?

解决方案

First of all, Activator.CreateInstance() is a right way.

But, there is a more interesting way that is:

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

Just create expression that calls 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() is long running operation

Just for curious.

这篇关于实例化一个类使用反射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆