搜索
您的当前位置:首页正文

C#中的反射原理及应用

来源:星星旅游

先来看一张图片

简单的理解就是,当C#代码在编译的时候,会将工程里面的类及其方法记录在metadata里面,然后利用System.reflection可以读取metadata记录的信息,从而就可以根据类型的实例拿到对应的类型和所有的类方法。

接下来是应用,看如下代码

场景1

通过获得一个实例的Type,然后利用这个Type去生成一个新得实例

namespace ConsoleApp1
{
    class Class1
    {
        public void Fun(int a, int b)
        {
            int res = a + b;
            Console.WriteLine($"Fun res is {res}");
        }

        public int val = 10;
    }
    
    static void Main(string[] args)
      {
          Class1 class_a = new Class1();
          Type a_type = class_a.GetType();
          dynamic aa = Activator.CreateInstance(a_type); // 根据一类类型动态创建一个新类实例
          Console.WriteLine(aa.GetType()); // 输出的结果是ConsoleApp1.Class1
          Console.WriteLine(aa.val); // 10
      }
 }

场景2

        static void Main(string[] args)
        {
        	//这里的绝对路径,找到你之前生成的dll文件
            Assembly assembly = Assembly.LoadFrom("E:/study_file/Pracfile/CStest1/ConsoleApp1/bin/Debug/netcoreapp3.1/ConsoleApp1.dll");
            Type cur_type = assembly.GetType("ConsoleApp1.Class1");
            dynamic cur_obj = Activator.CreateInstance(cur_type);
            Console.WriteLine($"res is : {cur_obj.GetType()}"); // res is : ConsoleApp1.Class1
        }

在这里是生成根据拿到的类型,生成实例的两个例子,下面介绍下获取对应类型方法及其调用的方式。代码如下:

namespace ConsoleApp1
{
    class Class1
    {
        public void Fun(int a, int b)
        {
            int res = a + b;
            Console.WriteLine($"a = {a} b = {b}");
        }

        public void Fun(int a, int b, int c) // 重载
        {
            int res = a + b;
            Console.WriteLine($"a = {a} b = {b} c = {c}");
        }

        public int val = 10;
    }
	
	        static void Main(string[] args)
        {
            Assembly assembly = Assembly.LoadFrom("E:/study_file/Pracfile/CStest1/ConsoleApp1/bin/Debug/netcoreapp3.1/ConsoleApp1.dll");//这里的绝对路径,找到你之前生成的dll文件
            Type cur_type = assembly.GetType("ConsoleApp1.Class1");
            dynamic cur_obj = Activator.CreateInstance(cur_type);// 生成个实例
            // 根据函数名字,以及参数列表Type类型获取对应的函数,获取保存在metadata中的数据信息
            MethodInfo methodInfo_a = cur_type.GetMethod("Fun",new Type[] { typeof(int), typeof(int)}); 
            methodInfo_a?.Invoke(cur_obj, new object[] { 3, 5 });
            MethodInfo methodInfo_b = cur_type.GetMethod("Fun", new Type[] { typeof(int), typeof(int), typeof(int) });
            methodInfo_b?.Invoke(cur_obj, new object[] { 3, 5, 7 }); // 调用对应的函数

        }
}

还有一些常用的函数接口,也简单的记录下

namespace ConsoleApp1
{
    class Class1
    {
        private void Test()
        {
            Console.WriteLine($"this is pricate Test !!!");
        }
        public void Fun(int a, int b)
        {
            int res = a + b;
            Console.WriteLine($"a = {a} b = {b}");
        }

        public void Fun(int a, int b, int c)
        {
            int res = a + b;
            Console.WriteLine($"a = {a} b = {b} c = {c}");
        }

        public int val = 10;
    }

 class Program
    {
        static void Main(string[] args)
        {
            Assembly assembly = Assembly.LoadFrom("E:/study_file/Pracfile/CStest1/ConsoleApp1/bin/Debug/netcoreapp3.1/ConsoleApp1.dll");//这里的绝对路径,找到你之前生成的dll文件
            Type cur_type = assembly.GetType("ConsoleApp1.Class1");
            dynamic cur_obj = Activator.CreateInstance(cur_type);
            //获取所有的函数列表
            MethodInfo[] methodInfos = cur_type.GetMethods(); 
            foreach(MethodInfo m in methodInfos)
            {

            }
            //获取单个函数
            MethodInfo methodInfo_a = cur_type.GetMethod("Fun", new Type[] { typeof(int), typeof(int), typeof(int) });
            methodInfo_a?.Invoke(cur_obj, new object[] { 1,2,3});
            //用 BindingFlags标记拿到的函数范围 这里表示的范围是实例中的非公有函数(private protect internal)
            MethodInfo methodInfo_b = cur_type.GetMethod("Test", BindingFlags.Instance | BindingFlags.NonPublic);
            methodInfo_b?.Invoke(cur_obj, null); // this is pricate Test !!!这里能直接调用私有函数,是不是很神奇
        }
    }
 }

因篇幅问题不能全部显示,请点此查看更多更全内容

Top