C#反射

news/2024/5/19 4:41:15 标签: c#, 反射

C#反射

  • 一、反射基础理论
    • 1.什么是程序集
    • 2.元数据
    • 3.反射的概念
    • 4.反射的作用
  • 二、相关API
    • Type
    • 获取类的程序集信息
    • 测试代码
    • 获取类中的公共成员
    • 获取所有的公共的构造函数并调用
    • 获取类中的公共成员变量
    • 获取类的公共方法
    • 其它相关的
  • 三、Assembly程序集类
  • 四、Activator(快速实例化对象)

一、反射基础理论

1.什么是程序集

  • 程序集是经由编译器得到的,供进一步编译的中间产物。
  • 在Windows系统中,它一般表现为.dll(库文件)或者是.exe(可执行文件)的格式。

2.元数据

  • 元数据就是用来描述数据的数据。
  • 程序中的类,类中的函数、变量等等信息就是程序的元数据。
  • 有关程序以及类型的数据被称为元数据,它们保存在程序集中。

3.反射的概念

  • 程序在运行时,可以查看其它程序集或自身的元数据
  • 一个运行的程序查看本身或者其他升序的元数据的行为叫做反射
  • 也就是说,在程序运行的时候,我们可以通过反射得到自身或者其他程序集的各种信息。来做我们想做的事情。

4.反射的作用

  • 因为反射可以在程序编译后获取信息,提高了程序的拓展性灵活性。
  • 程序运行时得到所有的元数据,包括元数据的特性
  • 程序运行时,实例化对象、操作对象
  • 程序在运行时创建新对象,用这些对象去执行任务

二、相关API

Type

Type(类的信息类)

  • 它是访问的基础
  • 它是访问元数据的主要方式
  • 使用Type的成员获取有关类型声明的成员信息(如构造函数、方法、字段、属性和类的事件等)

获取Type的三种方法
1.直接通过索要获取对象中的GetType()方法可以获取对象的Type。

 	int a = 42;
    Type type = a.GetType();
    Console.WriteLine(type);

打印的结果:
在这里插入图片描述
2.通过typeof关键字获取,传入类名,也可以得到对象的type

 Type type2 = typeof(int);
 Console.WriteLine(type2);

打印的结果为:
在这里插入图片描述
3.通过类名获取
类名必须要包括命名空间,否则访问不到
在这里插入图片描述

Type type3 = Type.GetType("System.Int32");
Console.WriteLine(type3);

在这里插入图片描述


说明:【上述三种获取都是得到了System.Int32,它们指向的地址是一样的!】


获取类的程序集信息

	int a = 42;
	Type type = a.GetType();
	Console.WriteLine(type.Assemble);

打印结果:
在这里插入图片描述

测试代码

测试代码
声明了一个测试类,用反射获取这个类相关的公共成员变量并执行它们。

class Test {
       
        private int i = 1;

        public int j = 0;

        public string str = "123";

        public Test() { }

        public Test(int i) {
            this.i = i;
        }

        public Test(int i,string str):this(i)
        {
            this.str = str;
        }

        public void Speak()
        {
            Console.WriteLine(i);
        }
    }

获取类中的公共成员

相关API: MemberInfo    Type.GetMembers()

	Type t = typeof(Test);
    //得到所有的公共成员变量
    MemberInfo[] infos = t.GetMembers();
    for (int i = 0; i < infos.Length; i++)
    {
   		 Console.WriteLine(infos[i]);
    }

在这里插入图片描述


获取所有的公共的构造函数并调用

相关API: ConstructorInfo   Type.GetConstructors()

	ConstructorInfo[] ctor = t.GetConstructors();
      for (int i = 0; i < ctor.Length; i++)
      {
            Console.WriteLine(ctor[i]);
      }

获取其中一个构造函数并执行

  • 在得到构造函数的时候,传入Type数组,数组中的内容顺序是参数类型
  • 在执行构造函数的时候,传入object数组,按照顺序传入参数

1.获取无参的构造函数

  • 因为这里没有参数,我们传入的数组声明为0就可以了
  ConstructorInfo info = t.GetConstructor(new Type[0]); 

执行无参构造
因为没有参数,传入null即可。

	info.Invoke(null);
    Test test = info.Invoke(null) as Test;

2.得到有参构造并且执行传递参数

//这里得到的是Test类中的一个参数的构造函数
 	ConstructorInfo info2 = t.GetConstructor(new Type[] { typeof(int) });
 	//传入参数的时候需要严格按照顺序传入
    info2.Invoke(new object[] { 3 });

    //这里得到的是Test两个参数的构造函数
    ConstructorInfo info3 = t.GetConstructor(new Type[] { typeof(int), typeof(string) });
    info3.Invoke(new object[] { 2, "356" });

获取类中的公共成员变量

相关API: FieldInfo    Type.GetFields()

 	FieldInfo[] fieldInfos = t.GetFields();
    for (int i = 0; i < fieldInfos.Length; i++)
    {
    	Console.WriteLine(fieldInfos[i]);
    }

1.获取指定名称的公共成员变量

//这里获取的是Test类中的j
 FieldInfo infoj = t.GetField("j");

2.通过反射获取和设置对象的值

	Test test2 = new Test();
    test2.j = 99;
    test2.str = "55555";

2.1通过反射获取对象的某个值
infoj.GetValue(test2) 将对象传递进去

Console.WriteLine("通过反射获取j的值为:"+infoj.GetValue(test2));

2.2通过反射设置指定某个变量的值

 	infoj.SetValue(test2, 6666)
    Console.WriteLine("通过反射设置的值为:"+infoj.GetValue(test2));

结果为:
在这里插入图片描述


获取类的公共方法

相关API:MethodInfo    Type.GetMethods()
这里得到string类中的方法为例

	Type strType = typeof(string);
	MethodInfo[] methods = strType.GetMethods();
    for (int i = 0; i < methods.Length; i++)
    {
        Console.WriteLine(methods[i]);
    }

1.如果存在方法的重载,使用type[]数组依次表示参数的类型 (这里获取的是指定方法)
1.method.Invoke(str,new object[] {1,2 }); 第一个str参数相当于哪个对象要执行这个方法,后边是object[]数组用于传递实参。
!!!这里需要说明的通过反射调用(执行)非静态的方法时,需要传递一个对象进去,而静态方法不需要传递对象进去,直接给一个null即可,因类静态方法是可以通过类名直接点出来的,而我们如果需要使用普通类中的公共成员,需要先实例化,然后才能使用它。!!!

	MethodInfo method = strType.GetMethod("Substring", new Type[] { typeof(int), typeof(int) });
	string str = "QWEQWERT";
	object obj= method.Invoke(str,new object[] {1,2 });
    Console.WriteLine(obj);

结果为:
在这里插入图片描述


其它相关的

枚举相关API:GetEnumsName  GetEnumsNames
事件相关API:GetEvent   GetEvents
接口相关API:GetInterface   GetInterfaces
属性相关API:GetProperty   GetPropertys


三、Assembly程序集类

C#通过反射调用外部程序集传送门

程序集类的作用:

 可以使用其它程序集的代码
  • 主要用于加载其它其它程序类,只有加载后才能用Type使用获取其它程序集中的信息。
  • 如果想要使用不是自己的程序集中的内容,需要先加载程序集(比如dll 库文件)

加载程序集的方式:
1.加载同一文件夹下的其它程序集

Assembly assembly = Assembly.Load(程序集所在路径);

2.加载不同文件夹下的其它程序集

 Assembly assembly = Assembly.LoadFrom(路径);
 Assembly assembly = Assembly.LoadFile(路径);

区别:

  1. Assembly.LoadFile()只载入相应的dll文件,路径写入哪个就加载哪一个。
  2. Assembly.LoadFrom()它会加载dll文件以及引用的其它dll文件
  3. 用Assembly.LoadFrom()载入一个Assembly时,会先检查自己是否已经载入过相同名字Assembly,如果有两个不同版本的相同名字的dll,载入第二个版本的dll会会返回第一个dll的文件,使用Assembly.LoadFile(),就能正确载入。

加载其它程序集的一般步骤:

  1. 先通过Assembly.LoadFile()Assembly.LoadFrom()加载程序集
  2. 在通过Type获取想要获取的类对象,之后才能使用反射
  3. 在通过反射调用,实力化对象

四、Activator(快速实例化对象)

作用:

  • 用于快速实例化对象的类
  • 用于将Type对象快捷实例化对象

先得到Type,然后快速实例化一个对象

 Type testType = typeof(Test);
 Activator.CreateInstance(testType);  //默认调用无参
 
 //通过里氏替换原则转换成Test
 Test t1= Activator.CreateInstance(testType) as Test;
 //调用的是Test中一个参数的构造
 Test t2=Activator.CreateInstance(testType, 99) as Test;
 //调用的是Test中两个参数的构造
 Test t3= Activator.CreateInstance(testType, 100,"sdsd") as Test;

http://www.niftyadmin.cn/n/884201.html

相关文章

Kalibr 安装+制作采集的图片和IMU数据生成 .bag 文件 (坑最全,解决方法最简单,最详细哈哈)

测试的数据集、标定板下载页面: https://github.com/ethz-asl/kalibr/wiki/downloads 官方下载和安装教程: https://github.com/ethz-asl/kalibr/wiki/installation Downloads ethz-asl/kalibr Wiki GitHub 方法一、Kalibr标定工具实现 (推荐) 1.0 安装依赖环境 sudo …

C#通过反射加载外部程序集(dll库文件)

C#通过反射加载外部程序集&#xff08;dll库文件&#xff09; 本文章使用了一个C#通过反射加载一个类库的dll文件&#xff0c;获取库文件中的公共成员&#xff0c;执行这些变量 反射基础整理传送门 说明&#xff1a; 这个dll文件和我们的反射不在同一个程序集中 测试代码 将这…

图片批量重命名(python实现)

自己在采集数据时&#xff0c;有时候的数据命名方式并不满足一些开源程序的条件&#xff0c;如果我们可以自己随意去改变图像的命名&#xff0c;问题 就变得很容易解决&#xff1b; 一、代码 import os path "/media/hltt3838/DATA/dida_data/20210421_camera_IMU/data…

Unity场景异步加载遇到的问题(进度条)

项目场景&#xff1a; 以前做的项目&#xff0c;突然甲方提供了较多的数据&#xff0c;测试加载场景中有点卡顿&#xff0c;改为一个异步加载场景用于过渡。避免太生硬的加载等待。 问题描述&#xff1a; 实现了场景的异步加载后&#xff0c;我一直觉得我这个加载有问题&#…

Ubuntu18.04 python2.7 升级python3.6,并切换版本

1. 在 终端ternimal输入命令 sudo apt-get install python3 //安装python3 安装完成之后&#xff0c;你在终端中输入python&#xff0c;输出的信息里面会提示是2.7版本的&#xff0c;也就是说默认打开的并不是刚才安装好的3.6&#xff0c;所以还需要…

C#中构造函数在继承关系中的规则

C#构造函数 说起构造函数&#xff0c;我们都知道是在实例化对象时&#xff0c;用于做一些初始化的操作&#xff0c;今天总结的是&#xff0c;在继承关系下的构造函数的执行关系&#xff0c;时间太长感觉拿捏不准了&#xff0c;好记性不如烂笔头,直接开始。 1.如果当前类存在继承…

Git学习 二、远程仓库

上一讲中https://blog.csdn.net/hltt3838/article/details/115253621&#xff0c; 我们已经掌握了如何在Git仓库里对一个文件进行时光穿梭&#xff0c;你再也不用担心文件备份或者丢失的问题了。 世界上有个叫GitHub的神奇的网站&#xff0c;从名字就可以看出&#xff0c;这个网…

Unity中使用MVC开发UI

MVC一、什么是MVC二、MVC小案例ModelViewController启动脚本三、小小小总结一、什么是MVC 说起MVC&#xff0c;可能都知道是Model--View--Controller,但是真要通透理解它的思想&#xff0c;还真是不容易。   何谓MVC呢&#xff1f;MVC开始是存在于桌面程序中的&#xff0c;M是…