zoukankan      html  css  js  c++  java
  • C#-反射reflection

    C#
    shanzm



    简介

    反射(reflection)是什么?
    在《精通C#》中是这么说的“反射就是一个运行库发现的过程”。

    举例来说,通过反射,可以得到一个给定的.dll或.exe程序集所包含的所有类型的列表,这个列表包括给定类型定义的方法、字段、属性和事件。



    引入

    1.新建类库

    右键解决方案->添加->新建项目->选择"类库"

    在类库项目中添加几个自定义的类(在《C#入门经典》中发现新建类可以使用VS中自带的类图添加,但是我感觉不是很方便,但是不得不承认VS的查看类图,对阅读项目代码还是很有帮助的)

    右键类库项目点击生成,在项目的binDeBug文件夹中生成相应的程序集文件(dll格式).

    2. 类库的使用

    如果某个项目要使用某个类库,则我们在项目中添加引用,引用类库项目,并添加引用的项目的命名空间。这样就可以使用类库中定义的类了。

    3.反射

    对于程序集文件(dll和exe文件),他们是二进制文件,不能直接打开,但是我们想要查看里面的具体内容,我们该怎么办。

    使用VS中的“对象浏览器”,直接右击引用文件,我们可以选择在对象浏览器中查看,就可以看到类库文件(dll文件)中的定义的类。

    还有一种方法那就是使用VS自带的反编译工具ildasm.exe(C:Program Files (x86)Microsoft SDKsWindowsv10.0AinNETFX 4.6.1 Toolsx64ildasm.exe)

    但是在代码中怎么查看呢,这就要用到反射。
    这就是动态加载程序集



    反射实例1

    在这里,我们把ClassLibrary1类库文件(dll文件)复制到项目的bin/Debug文件中

    ClassLibrary1类库有三个类具体如下
    程序集类图

    代码如下:

    namespace _01程序集的引用
    {
        class Program
        {
            static void Main(string[] args)
            {
                #region 加载程序集
                //获取基目录(也就是bindeBug的绝对路径)
                string deBuyPath = AppDomain.CurrentDomain.BaseDirectory;
    
                //获取DeBug中的dll文件的绝对路径(通过类库项目生成的,我自己复制到那里的)
                //using System.IO;
                string dllPath = Path.Combine(deBuyPath, "ClassLibrary1.dll");
    
                //加载程序集文件(using System.Reflection;)
                Assembly ass = Assembly.LoadFile(dllPath); 
                #endregion
    
    
                Console.WriteLine("获取程序集中所有定义的类的类名,包括internal和public");
                Type[] allTypes = ass.GetTypes();
                foreach (Type item in allTypes)
                {
                    Console.WriteLine($"程序集ClassLibrary1.dll中有类:{item.Name }");
                }
    
    
                //获取程序集中指定的类的类型
                Type p = ass.GetType("ClassLibrary1.Person");
                Console.WriteLine($"获取指定的类,类名{p.Name},类的命名空间{p.Namespace}");
    
    
                //获取所有程序集dll文件中定义的公共类型的类型(公共类)
                Type[] publicTypes = ass.GetExportedTypes();
    
    
                Console.ReadKey();
    
            }
        }
    }
    
    
    

    运行结果:

    -----------获取程序集中所有定义的类的类名,包括internal和public---------
    程序集ClassLibrary1.dll中有类:Person
    程序集ClassLibrary1.dll中有类:Student
    程序集ClassLibrary1.dll中有类:Teacher
    -----------获取程序集中指定的类的类型---------
    获取指定的类,类名Person,类的命名空间ClassLibrary1
    -----------获取程序集中公共类---------
    程序集ClassLibrary1.dll中的公共类有:Person
    程序集ClassLibrary1.dll中的公共类有:Student



    反射实例2

    namespace _02程序集的引用2
    {
        class Program
        {
            static void Main(string[] args)
            {
                //查询变量的类型
    
                //法1:已经声明了一个变量
                string str = "abcd";
                Type t1 = str.GetType();
                Console.WriteLine(t1);
    
                //法2:直接使用变量类型查询
                Type t2 = typeof(string);
                Console.WriteLine(t2);
    
                //法3:直接使用Type.GetType()静态方法
                Type t3 = Type.GetType("System.String");
                Console.WriteLine(t3);
    
                //我们可以获得string的类型名,我们可以使用类型对象来探测string类型的内部结构
                foreach (MemberInfo item in t1.GetMembers ())
                {
                    Console.WriteLine($"当前类型的公共成员类型{item.MemberType},成员名{item.Name }");
                }
    
    
                Console.ReadKey();
    
            }
        }
    }
    


    反射实例3

    反射实例1中我们知道了类库中的各个成员的的类型,那么我们怎么才能新建一个该类型的对象呢(这就是晚期加载
    注意啊,上面我们只是获得了各个类的类型(类名),并没有真正的获得这个类名这个变量
    所以我们无法使用类名这个变量去new一个对象

    建立程序集中类的对象

    
                //建立程序集中类的对象
                object person = Activator.CreateInstance(p, 24, "志铭", "男");
    
    
                #region 获取类型的属性
                //获取该对象的属性列表
                Console.WriteLine("--------获取该对象的属性列表---------");
                PropertyInfo[] pros = person.GetType().GetProperties();
                foreach (PropertyInfo item in pros)
                {
                    Console.WriteLine(item.Name);
                }
    
                //获得指定名称的属性
                PropertyInfo pro = p.GetProperty("Name");
                //获得对象person的指定的属性的值
                string name = (string)pro.GetValue(person, null);
                Console.WriteLine(name);
                #endregion
    
    
                #region 获取类型的方法列表
                Console.WriteLine("-------获取类型的方法列表--------------");
                MethodInfo[] methods = person.GetType().GetMethods();
                foreach (MethodInfo item in methods)
                {
                    Console.WriteLine(item.Name);
                }
    
                //调用指定名称的方法
                MethodInfo method = person.GetType().GetMethod("Say");
                method.Invoke(person, null);
                #endregion
    
                //获取字段列表(注意你只能获取公共类型的字段)
                FieldInfo[] fields = person.GetType().GetFields();
                foreach (FieldInfo item in fields)
                {
                    Console.WriteLine(item.Name);
                }
                
                Console.ReadKey();
    
    
  • 相关阅读:
    [NOIP2013] 提高组 洛谷P1979 华容道
    Vijos P1404 遭遇战
    CodeVS 1506 传话
    P1546 最短网络 Agri-Net
    HDU 4747 Mex
    POJ1020 Anniversary Cake
    【数据结构】平衡二叉树
    【数据结构】二叉排序树
    【数据结构】二叉树
    概念源于生活
  • 原文地址:https://www.cnblogs.com/shanzhiming/p/10371418.html
Copyright © 2011-2022 走看看