反射的定义:审查元数据并收集关于它的类型信息的能力。元数据(编译以后的最基本数据单元)就是一大堆的表,当编译程序集或者模块时,编译器会创建一个类定义表,一个字段定义表,和一个方法定义表等,。System.reflection命名空间包含的几个类,允许你反射(解析)这些元数据表的代码
反射的作用:
1.枚举类型成员
2 实例化新对象
3 执行对象的成员
4 查找类型的信息
5 查找程序集信息
6 检查应用于类型的定制特性
7 创建和编译新程序集
定制特性,定制特性允许把定制的元数据和程序元素关联起来。这些元素据是在编译过程中创建的,并嵌入到程序集中。接着就可以在运行期间使用反射的一些功能检查这些元数据了。
定制特性可以直接影响代码运行的方式。例如,定制特性可以用于支持对定制许可类进行声明代码访问安全检查,把信息与程序元素关联起来,由测试工具使用,或者在开发可扩展的架构时,允许加载插件或模块。
System.Type类
Type类,它只存储类型的引用:Type t = typeof(double)
Type是一个抽象的基类。只要实例化了一个Type对象,就实例化了Type的一个派生类。获取指向给定类型的Type引用有3种常用方式:
1.使用C#的typeof运算符,如上所示。这个运算符的参数是类型的名称。
2.使用GetType()方法,所有的类都会从System.Object继承这个类。
double d = 10;
Type t = d.GetType();
在一个变量上调用GetType(),而不是把类型的名称作为其参数。但要注意,返回的Type对象仍只与该数据类型相关:它不包含与类型实例相关的任何信息。如果有一个对象引用,但不能确保该对象实际上是哪个类的实例,这个方法也是很有用的。
3.还可以调用Type类的静态方法GetType():
Type t = Type.GetType("System.Double");
Type是许多反射技术的入口。注意,可用的属性都是只读的:可以使用Type确定数据的类型,但不能使用它修改该类型!
Type的属性
由Type执行的属性可以分为下述3类:
●有许多属性都可以获取包含与类相关的各种名称的字符串
Name,数据类型名
FullName,数据类型的完全限定名(包括命名空间名)
Namespace
●属性还可以进一步获取Type对象的引用,这些引用表示相关的类
BaseType,这个Type的直接基本类型
UnderlyingSystemType,这个Type在.NET 运行库中映射的类型 (某些.NET基类实际上映射由IL识别的特定预定义类型)
●许多Boolean 属性表示这个类型是一个类、还是一个枚举等。这些属性包括IsAbstract、IsArray、IsClass、IsEnum、IsInterface、IsPointer、IsPrimitive(一种预定义的基本数据类型)、IsPublic、IsSealed和IsValueType
Type的方法
System.Type的大多数方法都用于获取对应数据类型的成员信息:构造函数、属性、方法和事件等。它有许多方法,但它们都有相同的模式。例如,有两个方法可以获取数据类型的方法信息:GetMethod()和GetMethods()。GetMethod()方法返回System.Reflection.MethodInfo对象的一个引用,其中包含一个方法的信息。GetMethods()返回这种引用的一个数组。其区别是GetMethods()返回所有方法的信息,而GetMethod()返回一个方法的信息,其中该方法包含特定的参数列表。这两个方法都有重载方法,该重载方法有一个附加的参数,即BindingFlags枚举值,表示应返回哪些成员,例如,返回公有成员、实例成员和静态成员等。
Type t = typeof(double);
MethodInfo [] methods = t.GetMethods();
foreach (MethodInfo nextMethod in methods)
{
// etc.
}
Type的成员方法遵循同一个模式。
返回的对象类型 方法(名称为复数形式的方法返回一个数组)
ConstructorInfo GetConstructor(), GetConstructors()
EventInfo GetEvent(), GetEvents()
FieldInfo GetField(), GetFields()
InterfaceInfo GetInterface(), GetInterfaces()
MemberInfo GetMember(), GetMembers()
MethodInfo GetMethod(), GetMethods()
PropertyInfo GetProperty(), GetProperties()
GetMember()和GetMembers()方法返回数据类型的一个或所有成员的信息,这些成员可以是构造函数、属性和方法等。最后要注意,可以调用这些成员,其方式是调用Type的InvokeMember()方法,或者调用MethodInfo, PropertyInfo和其他类的Invoke()方法。
下面用一个短小的示例TypeView来说明Type类的一些功能:
using System;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
class MainClass
{
Static StringBuilder OutputText = new StringBuilder();
static void Main()
{
Type t = typeof(double);
AnalyzeType(t);
MessageBox.Show(OutputText.ToString(), "Analysis of type "+ t.Name);
Console.ReadLine();
}
static void AnalyzeType(Type t)
{
AddToOutput("Type Name: " + t.Name);
AddToOutput("Full Name: " + t.FullName);
AddToOutput("Namespace: " + t.Namespace);
Type tBase = t.BaseType;
if (tBase != null)
{
AddToOutput("Base Type:" + tBase.Name);
}
Type tUnderlyingSystem = t.UnderlyingSystemType;
if (tUnderlyingSystem != null)
{
AddToOutput("UnderlyingSystem Type:" + tUnderlyingSystem.Name);
}
AddToOutput("/nPUBLIC MEMBERS:");
MemberInfo [] Members = t.GetMembers();
foreach (MemberInfo NextMember in Members)
{
AddToOutput(NextMember.DeclaringType + " " +
NextMember.MemberType + " " + NextMember.Name);
}
}
static void AddToOutput(string Text)
{
OutputText.Append("/n" + Text);
}
Assembly类
Assembly类是在System.Reflection命名空间中定义的,它允许访问给定程序集的元数据,它也包含可以加载和执行程序集(假定该程序集是可执行的)的方法。
在使用Assembly实例做一些工作前,需要把相应的程序集加载到运行进程中。为此,可以使用静态成员Assembly.Load()或Assembly.LoadFrom()。这两个方法的区别是Load()的参数是程序集的名称,运行库会在各个位置上搜索该程序集,这些位置包括本地目录和全局程序集高速缓存。而LoadFrom()的参数是程序集的完整路径名,不会在其他位置搜索该程序集:
Assembly assembly1 = Assembly.Load("SomeAssembly");
Assembly assembly2 = Assembly.LoadFrom
(@"C:/My Projects/Software/SomeOtherAssembly");
这两个方法都有许多其他重载,它们提供了其他安全信息。加载了一个程序集后,就可以使用它的各种属性,例如查找它的全名:
string name = assembly1.FullName;
查找在程序集中定义的类型
Assembly类的一个特性是可以获得在相应程序集中定义的所有类型的信息,只要调用Assembly.GetTypes()方法,就可以返回一个包含所有类型信息的System.Type引用数组
Type[] types = theAssembly.GetTypes();
foreach(Type definedType in types)
{
DoSomethingWith(definedType);
}
查找定制特性
用于查找在程序集或类型中定义了什么定制特性的方法取决于与该特性相关的对象类型。如果要确定程序集中有什么定制特性,就需要调用Attribute类的一个静态方法GetCustomAttributes(),给它传递程序集的引用:
Attribute [] definedAttributes =
Attribute.GetCustomAttributes(assembly1);
// assembly1 is an Assembly object
示例:
using System;
using System.Reflection;
using System.Windows.Forms;
using System.Text;
using Wrox.ProCSharp.VectorClass;
using Wrox.ProCSharp.WhatsNewAttributes;
class WhatsNewChecker
{
static StringBuilder outputText = new StringBuilder(1000);
static DateTime backDateTo = new DateTime(2007, 2, 1);
static void Main()
{
Assembly theAssembly = Assembly.Load("VectorClass");
Attribute supportsAttribute =
Attribute.GetCustomAttribute(
theAssembly, typeof(SupportsWhatsNewAttribute));
string Name = theAssembly.FullName;
AddToMessage("Assembly: " + Name);
if (supportsAttribute == null)
{
AddToMessage( "This assembly does not support WhatsNew attributes");
return;
}
else
AddToMessage("Defined Types:");
Type[] types = theAssembly.GetTypes();
foreach(Type definedType in types)
DisplayTypeInfo(theAssembly, definedType);
MessageBox.Show(outputText.ToString(),
"What/'s New since " + backDateTo.ToLongDateString());
Console.ReadLine();
}
static void DisplayTypeInfo(Assembly theAssembly, Type type)
{
// make sure we only pick out classes
if (!(type.IsClass))
{
return;
}
AddToMessage("/nclass " + type.Name);
Attribute [] attribs = Attribute.GetCustomAttributes(type);
if (attribs.Length == 0)
{
AddToMessage("No changes to this class/n");
}
else
{
foreach (Attribute attrib in attribs)
{
WriteAttributeInfo(attrib);
}
}
MethodInfo [] methods = type.GetMethods();
AddToMessage("CHANGES TO METHODS OF THIS CLASS:");
foreach (MethodInfo nextMethod in methods)
{
object [] attribs2 =
nextMethod.GetCustomAttributes(
typeof(LastModifiedAttribute), false);
if (attribs != null)
{
AddToMessage(
nextMethod.ReturnType + " " + nextMethod.Name + "()");
foreach (Attribute nextAttrib in attribs2)
{
WriteAttributeInfo(nextAttrib);
}
}
}
}
static void WriteAttributeInfo(Attribute attrib)
{
LastModifiedAttribute lastModifiedAttrib =
attrib as LastModifiedAttribute;
if (lastModifiedAttrib == null)
{
return;
}
// check that date is in range
DateTime modifiedDate = lastModifiedAttrib.DateModified;
if (modifiedDate < backDateTo)
{
return;
}
AddToMessage(" MODIFIED: " +
modifiedDate.ToLongDateString() + ":");
AddToMessage(" " + lastModifiedAttrib.Changes);
if (lastModifiedAttrib.Issues != null)
{
AddToMessage(" Outstanding issues:" +
lastModifiedAttrib.Issues);
}
}
static void AddToMessage(string message)
{
outputText.Append("/n" + message);
}
}