通过反射命名空间中的类以及 System.Type,您可以获取有关已加载的程序集和在其中定义的类型(如类、接口和值类型)的信息。您也可以使用反射在运行时创建类型实例,然后调用和访问这些实例。
反射概述
公共语言运行库加载器管理应用程序域。这种管理包括将每个程序集加载到相应的应用程序域以及控制每个程序集中类型层次结构的内存布局。
程序集包含模块,而模块包含类型,类型又包含成员。反射则提供了封装程序集、模块和类型的对象。您可以使用反射动态地创建类型的实例,将类型绑定到现有对象,或从现有对象中获取类型。然后,可以调用类型的方法或访问其字段和属性。反射通常具有以下用途:
- 使用 Assembly 定义和加载程序集,加载在程序集清单中列出的模块,以及从此程序集中查找类型并创建该类型的实例。
- 使用 Module 了解如下的类似信息:包含模块的程序集以及模块中的类等。您还可以获取在模块上定义的所有全局方法或其他特定的非全局方法。
- 使用 ConstructorInfo 了解如下的类似信息:构造函数的名称、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 对象的 GetConstructors 或 GetConstructor 方法来调用特定的构造函数。
- 使用 MethodInfo 来了解如下的类似信息:方法的名称、返回类型、参数、访问修饰符(如 public 或 private)和实现详细信息(如 abstract 或 virtual)等。使用 Type 对象的 GetMethods 或 GetMethod 方法来调用特定的方法。
- 使用 FieldInfo 来了解如下的类似信息:字段的名称、访问修饰符(如 public 或 private)和实现详细信息(如 static)等;并获取或设置字段值。
- 使用 EventInfo 来了解如下的类似信息:事件的名称、事件处理程序数据类型、自定义属性、声明类型和反射类型等;并添加或移除事件处理程序。
- 使用 PropertyInfo 来了解如下的类似信息:属性的名称、数据类型、声明类型、反射类型和只读或可写状态等;并获取或设置属性值。
- 使用 ParameterInfo 来了解如下的类似信息:参数的名称、数据类型、参数是输入参数还是输出参数,以及参数在方法签名中的位置等。
System.Reflection.Emit 命名空间的类提供了一种特殊形式的反射,使您能够在运行时构造类型。
反射也可用于创建称作类型浏览器的应用程序,它使用户能够选择类型,然后查看有关选定类型的信息。
反射还有其他一些用途。JScript 等语言编译器使用反射来构造符号表。System.Runtime.Serialization 命名空间中的类使用反射来访问数据并确定要持久保存的字段。System.Runtime.Remoting 命名空间中的类通过序列化来间接地使用反射。
查看类型信息
System.Type 类对于反射起着核心的作用。当反射请求加载的类型时,公共语言运行库将为它创建一个 Type 对象。您可以使用 Type 对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。
在使用 Assembly.GetType 或 Assembly.GetTypes 时传入所需类型的名称,可以从尚未加载的程序集中获取 Type 对象。使用 Type.GetType 可从已加载的程序集中获取 Type 对象。使用 Module.GetType 和 Module.GetTypes 可获取模块 Type 对象。
以下代码示例显示在获取程序集的 Assembly 对象和模块时所必需的语法。
[C#]
// Get the mscorlib assembly in which the object is defined.
Assembly a = typeof(Object).Module.Assembly;
以下示例代码说明如何从已加载的程序集中获取 Type 对象。
[C#]
// Load an assembly using its file name.
Assembly a = Assembly.LoadFrom ("MyExe.exe");
// Get the type names from the assembly.
Type [] types2 = a.GetTypes ();
foreach (Type t in types2)
{
Console.WriteLine (t.FullName);
}
获取 Type 对象之后,可以通过多种方法来了解有关该类型成员的信息。例如,通过调用 Type.GetMembers 方法(该方法将获取对当前类型的每个成员进行描述的一组 MemberInfo 对象),您可以获取有关该类型的所有成员的信息。
您也可以在 Type 类上使用方法,以检索有关按名称指定的一个或多个构造函数、方法、事件、字段或属性的信息。例如,Type.GetConstructor 封装当前类的特定构造函数。
如果具有 Type 对象,则可以使用 Type.Module 属性来获取一个封装该类型所在模块的对象。使用 Module.Assembly 属性可查找封装模块所在程序集的对象。使用 Type.Assembly 属性可直接获取封装类型的程序集。
System.Type 和 ConstructorInfo
以下代码示例显示如何列出一个类(此示例中为 String 类)的构造函数。
[C#]
// This program lists all the public constructors
// of the System.String class.
using System;
using System.Reflection;
class ListMembers {
public static void Main(String[] args) {
Type t = typeof(System.String);
Console.WriteLine ("Listing all the public constructors of the {0} type", t);
// Constructors
ConstructorInfo[] ci = t.GetConstructors(BindingFlags.Public | BindingFlags.Instance);
Console.WriteLine ("//Constructors");
PrintMembers (ci);
}
public static void PrintMembers(MemberInfo [] ms) {
foreach (MemberInfo m in ms) {
Console.WriteLine ("{0}{1}", " ", m);
}
Console.WriteLine();
}
}
MemberInfo、MethodInfo、FieldInfo 和 PropertyInfo
使用 MemberInfo、MethodInfo、FieldInfo 或 PropertyInfo 对象可获取有关类型的方法、属性、事件、字段的信息。
以下代码示例使用 MemberInfo 来列出 System.IO.File 类中的成员数量并使用 System.Type.IsPublic 属性来确定该类的可见性。
[C#]
using System;
using System.IO;
using System.Reflection;
class Mymemberinfo
{
public static void Main(string[] args)
{
Console.WriteLine ("/nReflection.MemberInfo");
// Get the Type and MemberInfo.
Type MyType =Type.GetType("System.IO.File");
MemberInfo[] Mymemberinfoarray = MyType.GetMembers();
// Get and display the DeclaringType method.
Console.WriteLine("/nThere are {0} members in {1}.",
Mymemberinfoarray.Length, MyType.FullName);
Console.WriteLine("{0}.", MyType.FullName);
if (MyType.IsPublic)
{
Console.WriteLine("{0} is public.", MyType.FullName);
}
}
}
以下代码示例调查指定成员的类型。它对 MemberInfo 类的一个成员执行反射,然后列出其类型。
[C#]
// This code displays information about the GetValue method of FieldInfo.
using System;
using System.Reflection;
class MyMethodInfo {
public static int Main() {
Console.WriteLine("Reflection.MethodInfo");
// Get and display the Type.
Type MyType = Type.GetType("System.Reflection.FieldInfo");
// Specify the member for which you want type information here.
MethodInfo Mymethodinfo = MyType.GetMethod("GetValue");
Console.WriteLine(MyType.FullName + "." + Mymethodinfo.Name);
// Get and display the MemberType property.
MemberTypes Mymembertypes = Mymethodinfo.MemberType;
if (MemberTypes.Constructor == Mymembertypes) {
Console.WriteLine("MemberType is of type All");
}
else if (MemberTypes.Custom == Mymembertypes) {
Console.WriteLine("MemberType is of type Custom");
}
else if (MemberTypes.Event == Mymembertypes) {
Console.WriteLine("MemberType is of type Event");
}
else if (MemberTypes.Field == Mymembertypes) {
Console.WriteLine("MemberType is of type Field");
}
else if (MemberTypes.Method == Mymembertypes) {
Console.WriteLine("MemberType is of type Method");
}
else if (MemberTypes.Property == Mymembertypes) {
Console.WriteLine("MemberType is of type Property");
}
else if (MemberTypes.TypeInfo == Mymembertypes) {
Console.WriteLine("MemberType is of type TypeInfo");
}
return 0;
}
}
以下示例代码使用所有的反射 *Info 类以及 BindingFlags 来列出指定类的所有成员(构造函数、字段、属性、事件和方法),并将这些成员划分为静态和实例类别。
[C#]
// This program lists all the members of the
// System.IO.BufferedStream class.
using System;
using System.IO;
using System.Reflection;
class ListMembers {
public static void Main(String[] args) {
// Specify the class here.
Type t = typeof (System.IO.BufferedStream);
Console.WriteLine ("Listing all the members (public and non public) of the {0} type", t);
// Static Fields are listed first.
FieldInfo [] fi = t.GetFields (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("// Static Fields");
PrintMembers (fi);
// Static Properties
PropertyInfo [] pi = t.GetProperties (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("// Static Properties");
PrintMembers (pi);
// Static Events
EventInfo [] ei = t.GetEvents (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("// Static Events");
PrintMembers (ei);
// Static Methods
MethodInfo [] mi = t.GetMethods (BindingFlags.Static |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("// Static Methods");
PrintMembers (mi);
// Constructors
ConstructorInfo [] ci = t.GetConstructors (BindingFlags.Instance |
BindingFlags.NonPublic | BindingFlags.Public);
Console.WriteLine ("// Constructors");
PrintMembers (ci);
// Instance Fields
fi = t.GetFields (BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public);
Console.WriteLine ("// Instance Fields");
PrintMembers (fi);
// Instance Properites
pi = t.GetProperties (BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public);
Console.WriteLine ("// Instance Properties");
PrintMembers (pi);
// Instance Events
ei = t.GetEvents (BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public);
Console.WriteLine ("// Instance Events");
PrintMembers (ei);
// Instance Methods
mi = t.GetMethods (BindingFlags.Instance | BindingFlags.NonPublic |
BindingFlags.Public);
Console.WriteLine ("// Instance Methods");
PrintMembers (mi);
Console.WriteLine ("/r/nPress Return to exit.");
Console.Read();
}
public static void PrintMembers (MemberInfo [] ms) {
foreach (MemberInfo m in ms) {
Console.WriteLine ("{0}{1}", " ", m);
}
Console.WriteLine();
}
}