zl程序教程

您现在的位置是:首页 >  后端

当前栏目

【C#】反射说明书

c#反射 说明书
2023-09-11 14:14:50 时间

反射

反射提供描述程序集、模块和类型的对象(Type 类型)。 可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型,然后调用其方法或访问器字段和属性。 如果代码中使用了特性,可以利用反射来访问它们。

使用场景

  • 需要访问程序元数据的特性。
  • 检查和实例化程序集中的类型。
  • 在运行时构建新类型。使用System.Reflection.Emit中的类。
  • 执行后期绑定,访问在运行时创建的类型的方法。

形象说明

地球的内部结构:地球的内部结构大体可以分为三层:地壳、地幔和地核。地壳是固体,地核是液体,地幔则是半液半固的结构(地理知识)。如何在地球表面不用深入地球内部就知道其内部结构呢?答案是:向地球发射“地震波”。地震波分两种,一种是横波,另一种是纵波。横波只能穿透固体,而纵波既可以穿透固体又可以穿透液体。通过在地面对纵波和横波的返回情况,我们就可以大体断定地球内部的构造了。

B型超声波:大家体检的时候都做过B超吧,B超可以透过肚皮探测到你的内脏的生理情况。这是如何做到的呢?答案是:它可以透过肚皮向你体内发射B型超声波,当超声波遇到内脏壁的时候就会产生一定的“回音”反射,然后把“回音”进行处理就可以显示出你的内脏的情况了。(部分细节不予追究)

大家注意到这两个例子的共同特点,就是从一个对象的外部去了解对象内部的构造,而且都是利用了波的反射功能。在.NET中的反射也可以实现从对象的外部来了解对象(或程序集)内部结构的功能,哪怕你不知道这个对象(或程序集)是什么,另外.NET中的反射还可以动态创建出对象并执行它其中的方法。

反射是.NET中重要的机制,通过反射,可以在运行时获得程序或程序集中每一个类型(包括类、结构、委托、接口和枚举等)的成员和成员的信息。有了反射,即可对每一个类型了如指掌。另外我还可以直接创建对象,即使这个对象的类型在编译时还不知道。

反射的用途

(1)使用Assembly定义和加载程序集,加载在程序集中的所有模块以及从此程序集中查找类型并创建该类型的实例。
(2)使用Module了解包含模块的程序集以及模块中的类等,还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解构造函数的名称、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(4)使用MethodInfo了解方法的名称、返回类型、参数、访问修饰符(如pulic 或private)和实现详细信息(如abstract或virtual)等。
(5)使用FiedInfo了解字段的名称、访问修饰符(如public或private)和实现详细信息(如static)等,并获取或设置字段值。
(6)使用EventInfo了解事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等,添加或移除事件处理程序。
(7)使用PropertyInfo了解属性的名称、数据类型、声明类型、反射类型和只读或可写状态等,获取或设置属性值。
(8)使用ParameterInfo了解参数的名称、数据类型、是输入参数还是输出参数,以及参数在方法签名中的位置等。

反射用到的命名空间

  • System.Reflection
  • System.Type
  • System.Reflection.Assembly

反射用到的主要类

  • System.Type 类--通过这个类可以访问任何给定数据类型的信息。
  • System.Reflection.Assembly 类--它可以用于访问给定程序集的信息,或者把这个程序集加载到程序中

栗子

一个最简单的C#反射实例,首先编写类库如下:

namespace ReflectionTest
{ 
	public class WriteTest 
	{ 
		//带参数的公共方法
		public void WriteString(string s, int i) 
		{ 
		Console.WriteLine("WriteString:" + s + i.ToString()); 
		} 
		//带一个参数的静态方法
		public static void StaticWriteString(string s)
		{ 
		Console.WriteLine("StaticWriteString:" + s); 
		} 
		//不带参数的静态方法
		public static void NoneParaWriteString() 
		{ 
		Console.WriteLine("NoParaWriteString"); 
		} 
	} 
}

控制台程序项目如下:

class TestApp
{ 
	public static void Main() 
	{ 
		Assembly ass; 
		Type type; 
		Object obj; 
		//用来测试静态方法
		Object any = new Object(); 
		//指定类库文件必须使用绝对路径,不能使用相对路径
		ass = Assembly.LoadFile(@"D:\Source Code\00.C#Sudy\01.Reflection\01\ReflectTest.dll"); 
		//命名空间和类的名字必须一起指定 
		type = ass.GetType("ReflectionTest.WriteTest"); 
		/**//*example1---------*/ 
		MethodInfo method = type.GetMethod("WriteString"); 
		string test = "test"; 
		int i = 1; 
		Object[] parametors = new Object[]{test,i}; 
		//在例子1种必须实例化反射要反射的类,因为要使用的方法并不是静态方法。
		//创建对象实例
		obj = ass.CreateInstance("ReflectionTest.WriteTest"); //执行带参数的公共方法
		method.Invoke(obj, parametors); 
		//method.Invoke(any, parametors);//异常:必须实例化反射要反射的类,因为要使用的方法并不是静态方法。
		/**//*example2----------*/ 
		method = type.GetMethod("StaticWriteString"); 
		method.Invoke(null, new string[] { "test"}); //第一个参数忽略//对于第一个参数是无视的,也就是我们写什么都不会被调用,
		//即使我们随便new了一个any这样的Object,当然这种写法是不推荐的。
		//但是对应在例子1种我们如果Invoke的时候用了类型不一致的实例来做为参数的话,将会导致一个运行时的错误。
		method.Invoke(obj, new string[] { "test"});
		method.Invoke(any, new string[] { "test"});
		/**//*example3-----------*/ 
		method = type.GetMethod("NoneParaWriteString"); //调用无参数静态方法的例子,这时候两个参数我们都不需要指定,用null就可以了。method.Invoke(null, null); 
	} 
}

来源

c# 中反射里的invoke方法的参数
C#反射详解