C#深入学习--反射

目录

 

一、概述

二、基本使用

2.1 获取程序类容基本步骤

2.2 使用举例

2.2.1 创建对象&访问设置属性值&使用其中无参方法

2.2.2 创建带参构造函数并访问其中带参方法

2.2.3 反射重载过的方法

2.2.4 反射泛型类和泛型方法

2.2.5 反射类型中的私有类容(属性&方法&...)

2.2.6 反射类型中的Attribute

三 、反射特点


一、概述

我们之所以能看见这个世界万事万物,不是万物能发光,而是因为它们反射了太阳的光芒。在C#代码世界里,我们的代码被编译为一个个DLL和EXE ,同样,也有这样一束光能让我们看清DLL和EXE中我们定义的各个类/属性等等一切。这束光就是 using System.Reflection; 看清并使用里面的内容的过程就是反射。

二、基本使用

2.1 获取程序类容基本步骤

a. 加载程序集

b.获得程序集中类型

c.获得其中属性/方法/字段

基本操作代码如下

            {
                //第一步,根据{程序集名称}加载程序集,可以指定完整路径,否则从当前运行目录寻找
                Assembly assembly = Assembly.Load("XiaoMiTV"); 
                //第二步,获取程序中所有的类型TYPE
                Type[] types = assembly.GetTypes();               //获取程序集中所有的Type,也就是程序集中包含的所有C#类型(类,接口,委托,结构...)
                Type type = assembly.GetType("XiaoMiTV.XiaoMi");  //获取指定Type名称(包含命名空间)的Type
                //第三步,获取Type中的类容
                PropertyInfo[] props = type.GetProperties();      //获得type中的所有属性
                var prop = type.GetProperty("propName");          //根据指定名称获取属性
                FieldInfo[] fields = type.GetFields();            //获取type中的所有字段
                FieldInfo field = type.GetField("FildName");      //根据指定名称获取字段
                MethodInfo[] methods = type.GetMethods();         //获取type中所有方法
                MethodInfo method = type.GetMethod("MethodName"); //根据指定名称获取方法
            }

2.2 使用举例

2.2.1 创建对象&访问设置属性值&使用其中无参方法

                var assembly = Assembly.Load("XiaoMiTV");
                var type = assembly.GetType("XiaoMiTV.XiaoMi");
                /*
                 *  创建对象实例
                 *  CreateInstance(Type type,params object[] args) 
                 *  参数:Type             => 要创建实例的类型
                 *        params object[]  => 构造函数参数组,无参构造传入null 
                 */
                object objTv = Activator.CreateInstance(type, null);

                // objTv.Id = 5;                        // 编译报错,object 并没有Id属性
                var prop = type.GetProperty("Id");      // 根据Id获取 Id属性
                prop.SetValue(objTv, 5);                // 设置objTv对象中Id属性值
                var propValue = prop.GetValue(objTv);   // 获取objTv对象中Id属性值 


                var Show = type.GetMethod("Show");      //获取type中的Show方法
                /* 
                 * 执行Show方法
                 * XXMethod.Invoke(object obj,object[] args)
                 * 参数:
                 *      object obj        =>该方法执行载体,在哪个具体实例中执行
                 *      object[] args     =>执行该方法的参数组,无参数则为null
                 */
                Show.Invoke(objTv, null);

注意事项:

1. Activator.CreateInstance(type,null);返回的是object对象,无法直接访问Id属性,可以转换如下,但是不推荐。后续文章会有专门的解决方案

                //用dynamic 替换 object ,躲过编译器检查 
                //但是会出现安全问题,如果选择了一个不存在的属性,运行的时候就报错
                dynamic dynamicTv = Activator.CreateInstance(type, null);
                dynamicTv.Id = 3; 

2. XXMethod.Invoke(object obj,object[] args); obj 参数,执行载体,其实就是为这个方法提供执行上下文。执行上下文不一样,结果可能会不一样(如果它用到载体中的一些元素)

3. prop.SetValue() 和 prop.GetValue() 一定要指定到具体对象实例

2.2.2 创建带参构造函数并访问其中带参方法

            {
                var assembly = Assembly.Load("XiaoMiTV");
                var type = assembly.GetType("XiaoMiTV.XiaoMi");
                var obj = Activator.CreateInstance(type, new object[] { "Nemo" }); //带一个string类型的构造参数
                var ShutDown = type.GetMethod("ShutDown");
                var re = ShutDown.Invoke(obj, new object[] { 5 }); // 带一个int类型的方法
            }

注意事项:

1. 我只举例单个参数,多个参数的话,直接在 new object[]{}中依次添加。

2. 若方法有返回值,直接也可以获取,不过是 object类型,使用的是后进行强转。

2.2.3 反射重载过的方法

就是在寻找方法的时候加上重载类型如下:

                /* 反射如下Reload的方法
                 * public void Reload(string name,int sec); 
                 */
                var Reload = type.GetMethod("Reload", new Type[] { typeof(string), typeof(int) });

                /* 反射如下Reload的方法
                * public void Reload(int sec); 
                */
                var Reload1 = type.GetMethod("Reload", new Type[] { typeof(int) });

2.2.4 反射泛型类和泛型方法

                var assembly = Assembly.Load("XiaoMiTV");
                var GenericType = assembly.GetType("XiaoMiTV.GenericT`1")  //`1 表示该类有一个占位(泛型参数)
                    .MakeGenericType(new Type[] { typeof(int) });          //表示要创建对象实例时传入的指定类型为int
                var GenericMethod = GenericType.GetMethod("MethTest")
                    .MakeGenericMethod(new Type[] { typeof(int) });        //指定调用该方法传入的泛型类型为string
                GenericMethod.Invoke(GenericType, new object[] { 2 });     //调用泛型方法

注意事项:

1. 占位符用 `2 表示有两个泛型类型。“`” 是键盘第二排第一个英文状态下的符号。

2.在指定泛型具体类型时候要注意和原对象泛型顺序一致。

2.2.5 反射类型中的私有类容(属性&方法&...)

var methodShow = typeSingleton.GetMethod("Show",BindingFlags.NonPublic | BindingFlags.Instance);

就是在 GetXXX 方法中添加 BindingFlags 选项。还有很多其他选项,需要的时候可以看看

2.2.6 反射类型中的Attribute

                var assembly = Assembly.Load("XiaoMiTV");
                var type = assembly.GetType("XiaoMiTV.XiaoMi");
                IEnumerable<Attribute> typeAttrs =  type.GetCustomAttributes();     //获取对象上的所有Attribute
                var prop = type.GetProperty("Id");
                IEnumerable<Attribute> propAttrs = prop.GetCustomAttributes();      //获取属性上的所有Attribute
                var Method = type.GetMethod("Show");
                IEnumerable<Attribute> methodAttrs = Method.GetCustomAttributes();  //获取方法上的所欲Attribute

注意事项:

XX.GetCustomAttibutes中获取一个枚举类型的结果,然后可以进一步处理(下面章节Attribut会提到)

三 、反射特点

1.动态加载dll,根据字符串就可以创建对象实例并使用,减少了对象间依赖

2.突破私有权限,可以访问私有内容(方法$属性...)

3.性能较差

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值