C#反射详解及其性能分析-学习分享

参考源码:https://gitee.com/chenheze90/lc01_-reflect-l/tree/master/

C#反射详解及其性能分析

我们首先盘点一下代码语言的运作过程

  • 第一步,用C#写代码
    C#是一种高级语言,是人类所用和掌握的开发语言,是为了方便人类开发而生的。但是它并不是直接运行在系统上的。
  • 第二步,编译成中间语言
    通过VS中的编译器,C#编译成中间语言IL,并打包进.dll文件中。其实dll中除了中间语言IL之外,还包含metadata元数据数据清单,记录了dll中包含了哪些东西,是一个描述。ILSpy是一款正对IL语言的反编译工具,可以将dll中的中间语言反编译成C#;
  • 第三步,中间语言转化成本地及其语言
    这个时候的编译器叫JIT(即时编译器)将IL转化成本地机器语言。

支持软件是第一步到第二部再到第三步。我们本次讲的反射是反过来的,从第二部到第一步。

反射

简单反射获取实例

private static void Reflex1()
{
	//第一种方法:直接加载dll
    //Assembly assembly = Assembly.LoadFrom("LC01_Reflect.dll");
    //第二种方法:提供路径的加载dll
    //Assembly assembly = Assembly.LoadFile(@"X://xxx.dll");
    //第三种方法:经常用到,被反射的dll存在被替换的情况。本文中的所有情况,都会占用dll资源,导致无法覆盖dll
    //byte[] filedata = File.ReadAllBytes("ATL.AutoTestReport.TestItems.dll");
    //Assembly assembly = Assembly.Load(filedata);
    Assembly assembly = Assembly.Load("LC01_Reflect");//不论是exe还是dll都可以加载

    Type type1 = assembly.GetType("LC01_Reflect.Person");
    object c = Activator.CreateInstance(type1);
    Person s = c as Person;
}

项目内部反射

项目内部反射不再使用Assembly.Load方法,效率提高。

Assembly assembly = Assembly.GetExecutingAssembly();
object obj = assembly.CreateInstance("LC01_Reflect.Person");
//或者
Type type = Type.GetType("LC01_Reflect.Person");
obj = Activator.CreateInstance(type);
Person s = obj as Person;

通过反射调用类内部方法

Assembly assembly = Assembly.Load("LC01_Reflect");
Type type = assembly.GetType("LC01_Reflect.Person");
object oInstance = Activator.CreateInstance(type);
MethodInfo method = type.GetMethod("Say");
// 无参数方法调用
//method.Invoke(oInstance, new object[] { });
//method.Invoke(oInstance, new object[0]);
//method.Invoke(oInstance, null);
// 有参数方法调用
method.Invoke(oInstance, new object[] {"222" });
// 私有方法调用
MethodInfo method2 = type.GetMethod("PSay", BindingFlags.NonPublic | BindingFlags.Instance);
method2.Invoke(oInstance, new object[] { "String" });
// 静态方法
MethodInfo method3 = type.GetMethod("SSay", BindingFlags.Public | BindingFlags.Static);
method3.Invoke(null, new object[] { "333" });

通过反射调用字段及其属性

Assembly assembly = Assembly.Load("LC01_Reflect");
Type type = assembly.GetType("LC01_Reflect.Person");
object oInstance = Activator.CreateInstance(type);
PropertyInfo propertyInfo = type.GetProperty("Name");
propertyInfo.SetValue(oInstance, "sssss");
object resName = propertyInfo.GetValue(oInstance);

FieldInfo filedinfo = type.GetField("age");
filedinfo.SetValue(oInstance, 5);
object resAge = filedinfo.GetValue(oInstance);

控制台代码及其之后结果展示

static void Main(string[] args)
{
    //普通反射
    Reflex1();

    //内部反射
    Reflex2();

    //通过反射调用方法
    Reflex3();

    Console.Read();
}

在这里插入图片描述

反射的性能

public static void Show()
{
   Console.WriteLine("*******************测试性能*******************");
   long commonTime = 0;
   long reflectionTime = 0;
   {
       Stopwatch watch = new Stopwatch();
       watch.Start();
       for (int i = 0; i < 1000_000; i++) 
       {
           Person person = new Person();
           //person.Say("Test");
       }
       watch.Stop();
       commonTime = watch.ElapsedMilliseconds;
   }
   {
       Stopwatch watch = new Stopwatch();
       watch.Start();
       Assembly assembly = Assembly.Load("LC01_Reflect");//1 动态加载
       Type type1 = assembly.GetType("LC01_Reflect.Person");//2 获取类型  
       for (int i = 0; i < 1000_000; i++)
       {
           object person = Activator.CreateInstance(type1);//3 创建对象                    
       }
       watch.Stop();
       reflectionTime = watch.ElapsedMilliseconds;
   }
   Console.WriteLine($"正常new实例化时间:{commonTime}ms, 反射时间:{reflectionTime}ms");
}

测试的结果
在这里插入图片描述
实验结果:一百万次的代码执行,实例化是8ms,反射61ms,后者还包含了Load的方法所需的时间。

反射使用的场景和建议
1.反射本身有性能问题,但是影响不大,除非反复使用。所以反射忌讳的是大量的反复使用;
2.反射适合用在架构搭建阶段,它提高了程序的灵活性和扩展性。
3.反射可以用在软件的拓展设计方面给,它降低耦合性,提高自适应能力。
4.可以方便和其他程序的对接,它允许程序创建和控制任何类的对象,无需提前硬编码目标类,不用管理对方的代码而使用对方提供的功能。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值