C#中的反射原理及应用

24 篇文章 0 订阅
7 篇文章 1 订阅

先来看一张图片

在这里插入图片描述
逆向工程,可以把Dll/Exe文件反编译回来,IL是对标于C#代码的代码,metadata是一个清单数据,记录里面包含什么而不是细节的具体实现;
1.反射的原理:
反射是System.Reflection命名空间,可以读取metadata,并使用metadata,是微软提供的一个帮助类,在各个场景中都会使用到,而其主要作用是“解耦”,降低对细节的依赖。

简单的理解就是,当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

创建dll中的实例,这里为了方便,将上述工程生成解决方案,在其bin目录下就会有对应的dll文件,代码如下:

        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 !!!这里能直接调用私有函数,是不是很神奇
        }
    }
 }

参考文档

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值