C#反射
首先我们可以先来了解下什么是反射
Reflection,中文翻译为反射。
这是.Net中获取运行时类型信息的方式,.Net的应用程序由几个部分:‘程序集(Assembly)’、‘模块(Module)’、‘类型 (class)’组成,而反射提供一种编程的方式,让程序员可以在程序运行期获得这几个组成部分的相关信息,例如:
Assembly类可以获得正在运行的装配件信息,也可以动态的加载装配件,以及在装配件中查找类型信息,并创建该类型的实例。
Type类可以获得对象的类型信息,此信息包含对象的所有要素:方法、构造器、属性等等,通过Type类可以得到这些要素的信息,并且调用之。
MethodInfo包含方法的信息,通过这个类可以得到方法的名称、参数、返回值等,并且可以调用之。
诸如此类,还有FieldInfo、EventInfo等等,这些类都包含在System.Reflection命名空间下。
程序代码在编译后生成可执行的应用,我们要了解这种可执行应用程序的结构。
程序集包含模块,而模块包含类型,类型又包含成员。
反射则提供了封装程序集、模块和类型的对象。
您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。
然后,可以调用类型的方法或访问其字段和属性。
反射通常具有以下用途:
1.使用 Assembly 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
2.使用 Module 了解如下的类似信息:包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
3.使用 ConstructorInfo 了解以下信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。
4.使用 MethodInfo 了解以下信息:方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 的 GetMethods 或 GetMethod 方法来调用特定的方法。
5.使用 FieldInfo 了解以下信息:字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。
6.使用 EventInfo 来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
7.使用 EventInfo 来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
8.使用 ParameterInfo 来了解如下的类似信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。
9.当您在一个应用程序域的仅反射上下文中工作时,请使用 CustomAttributeData 来了解有关自定义属性的信息。使用 CustomAttributeData,您不必创建属性的实例就可以检查它们。
下面我们通过实例代码来看一下:
public class Person { public string Name; private int _Age; public int Age { get { return _Age; } set { _Age = value; } } public Person(string Name) { this.Name = Name; } public void DisplayInfo(string info) { System.Console.WriteLine(info); System.Console.WriteLine("called sucessfully!"); } public void DisplayName() { System.Console.WriteLine(Name); } public string getName() { return Name; } }
首先我创建了一个控制台的应用程序,然后定义一个实体Person类。
接下来就来看看Main函数中的实现代码吧。
static void Main(string[] args) { //从Dll中加载 //Assembly ass = Assembly.LoadFile(@"TestReflect.dll"); //Type myType = ass.GetType("testReflection.Person"); //object aPerson = ass.CreateInstance("Person"); //取得类型 Type myType = Type.GetType("testReflection.Person"); //构造函数要用到的参数 object[] constuctParms = new object[] { "Brad Pitt" }; //创建实例 //object TestName = Assembly.GetAssembly(myType).CreateInstance("Person"); object aPerson = Activator.CreateInstance(myType, constuctParms); //使用MethodInfo 和Invoke 调用方法 MethodInfo displayInfoMethod = myType.GetMethod("DisplayInfo"); displayInfoMethod.Invoke(aPerson, new object[] { "Using Invoke to call Method DisplayInfo()" }); //使用InvokeMember 调用方法 //调用方法的一些标志位 BindingFlags flag = BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Instance; myType.InvokeMember("DisplayInfo", flag, null, aPerson, new object[] { "Using InvokeMethod to call DisplayInfo()" }); //如果方法有返回值 string name = (string)myType.InvokeMember("getName", flag, null, aPerson, null); System.Console.WriteLine("call getName(), return: " + name); //设置属性值 myType.InvokeMember("Age", BindingFlags.SetProperty, null, aPerson, new object[] { 30 }); //得到属性值 int age = (int)myType.InvokeMember("Age", BindingFlags.GetProperty, null, aPerson, null); System.Console.WriteLine("Get the property of Age : " + Convert.ToString(age)); //设置字段值 myType.InvokeMember("Name", BindingFlags.SetField, null, aPerson, new object[] { "Michal Jodn" }); //获取字段值 string fname = (string)myType.InvokeMember("Name", BindingFlags.GetField, null, aPerson, null); System.Console.WriteLine("Get the Field Value of Name : " + fname); myType.InvokeMember("DisplayName", flag, null, aPerson, null); //获得方法集 MethodInfo[] methods = myType.GetMethods(); foreach (MethodInfo m in methods) { System.Console.WriteLine(m.Name); } //同样还有:GetFiedls()、GetProperties()、GetEvents()等方法 //使用Delegate //此方法是静态的,所以必须提供委托类型。 TestDelegate dg = (TestDelegate)Delegate.CreateDelegate(typeof(testReflection.TestDelegate), aPerson, "DisplayInfo"); dg("Test Delegate by call DisplayInfo()"); //获得解决方案的所有Assembly Assembly[] AX = AppDomain.CurrentDomain.GetAssemblies(); //遍历显示每个Assembly的名字 foreach (object var in AX) { Console.WriteLine("Assembly的名字:" + var.ToString()); } //使用一个已知的Assembly名称,来创建一个Assembly //通过CodeBase属性显示最初指定的程序集的位置 Console.WriteLine("最初指定的程序集TestReflection的位置:" + Assembly.Load("TestReflection").CodeBase); System.Console.ReadLine(); }
说明:
您也可以直接下载代码进行调试查看 示例代码
使用反射动态调用类成员,需要Type类的一个方法:InvokeMember。对该方法的声明如下:
public object InvokeMember(
string name,
BindingFlags invokeAttr,
Binder binder,
object target,
object[] args
);
参数
name
String,它包含要调用的构造函数、方法、属性或字段成员的名称。
- 或 -
空字符串 (""),表示调用默认成员。
invokeAttr
一个位屏蔽,由一个或多个指定搜索执行方式的 BindingFlags 组成。访问可以是 BindingFlags 之一,如 Public、NonPublic、Private、InvokeMethod 和 GetField 等。不需要指定查找类型。如果省略查找类型,则将应用 BindingFlags.Public | BindingFlags.Instance。
binder
一个 Binder 对象,该对象定义一组属性并启用绑定,而绑定可能涉及选择重载方法、强制参数类型和通过反射调用成员。
- 或 -
若为空引用(Visual Basic 中为 Nothing),则使用 DefaultBinder。
target
在其上调用指定成员的 Object。
args
包含传递给要调用的成员的参数的数组。
返回值
表示被调用成员的返回值的 Object。
下列 BindingFlags 筛选标志可用于定义包含在搜索中的成员:
为了获取返回值,必须指定 BindingFlags.Instance 或 BindingFlags.Static。
指定 BindingFlags.Public 可在搜索中包含公共成员。
指定 BindingFlags.NonPublic 可在搜索中包含非公共成员(即私有成员和受保护的成员)。
指定 BindingFlags.FlattenHierarchy 可包含层次结构上的静态成员。
下列 BindingFlags 修饰符标志可用于更改搜索的执行方式:
BindingFlags.IgnoreCase,表示忽略 name 的大小写。
BindingFlags.DeclaredOnly,仅搜索 Type 上声明的成员,而不搜索被简单继承的成员。
可以使用下列 BindingFlags 调用标志表示要对成员采取的操作:
CreateInstance,表示调用构造函数。忽略 name。对其他调用标志无效。
InvokeMethod,表示调用方法,而不调用构造函数或类型初始值设定项。
对 SetField 或 SetProperty 无效。
GetField,表示获取字段值。对 SetField 无效。
SetField,表示设置字段值。对 GetField 无效。
GetProperty,表示获取属性。对 SetProperty 无效。
SetProperty 表示设置属性。对 GetProperty 无效。