C#反射

一、反射基础理论

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;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值