page contents

C#反射的实现原理及应用

本文讲述了C#反射的实现原理及应用!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

attachments-2022-07-765fpbNZ62ce29ee2817a.png

本文讲述了C#反射的实现原理及应用!具有很好的参考价值,希望对大家有所帮助。一起跟随六星小编过来看看吧,具体如下:

先来看一张图片

attachments-2022-07-QiBSU9n562ce2959bb872.png

逆向工程,可以把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 !!!这里能直接调用私有函数,是不是很神奇

        }

    }

 }

更多相关技术内容咨询欢迎前往并持续关注六星社区了解详情。

想高效系统的学习Python编程语言,推荐大家关注一个微信公众号:Python编程学习圈。每天分享行业资讯、技术干货供大家阅读,关注即可免费领取整套Python入门到进阶的学习资料以及教程,感兴趣的小伙伴赶紧行动起来吧。

attachments-2022-05-rLS4AIF8628ee5f3b7e12.jpg

  • 发表于 2022-07-13 10:11
  • 阅读 ( 339 )
  • 分类:C/C++开发

你可能感兴趣的文章

相关问题

0 条评论

请先 登录 后评论
轩辕小不懂
轩辕小不懂

2403 篇文章

作家榜 »

  1. 轩辕小不懂 2403 文章
  2. 小柒 1474 文章
  3. Pack 1135 文章
  4. Nen 576 文章
  5. 王昭君 209 文章
  6. 文双 71 文章
  7. 小威 64 文章
  8. Cara 36 文章