反射学习笔记三(转载)
2010-02-24 15:48 爱研究源码的javaer 阅读(211) 评论(0) 编辑 收藏 举报namespace Demo {
public abstract class BaseClass {
}
public struct DemoStruct { }
public delegate void DemoDelegate(Object sender, EventArgs e);
public enum DemoEnum {
terrible, bad, common=4, good, wonderful=8
}
public interface IDemoInterface {
void SayGreeting(string name);
}
public interface IDemoInterface2 {}
public sealed class DemoClass:BaseClass, IDemoInterface,IDemoInterface2 {
private string name;
public string city;
public readonly string title;
public const string text = "Const Field";
public event DemoDelegate myEvent;
public string Name {
private get { return name; }
set { name = value; }
}
public DemoClass() {
title = "Readonly Field";
}
public class NestedClass { }
public void SayGreeting(string name) {
Console.WriteLine("Morning :" + name);
}
}
}
现在我们在 SimpleExplore项目中写一个方法AssemblyExplor(),查看我们Demo项目生成的程序集Demo.dll定义的全部类型:
public static void AssemblyExplore() {
StringBuilder sb = new StringBuilder();
Assembly asm = Assembly.Load("Demo");
sb.Append("FullName(全名):" + asm.FullName + "\n");
sb.Append("Location(路径):" + asm.Location + "\n");
Type[] types = asm.GetTypes();
foreach (Type t in types) {
sb.Append(" 类型:" + t + "\n");
}
Console.WriteLine(sb.ToString());
}
然后,我们在Main()方法中调用一下,应该可以看到这样的输出结果:
FullName(全名):Demo, Version=
Location(路径):E:\MyApp\TypeExplorer\SimpleExplorer\bin\Debug\Demo.dll
模块: Demo.dll
类型:Demo.BaseClass
类型:Demo.DemoStruct
类型:Demo.DemoDelegate
类型:Demo.DemoEnum
类型:Demo.IDemoInterface
类型:Demo.IDemoInterface2
类型:Demo.DemoClass
类型:Demo.DemoClass+NestedClass
反射基本类型
这里说反射基本类型,基本类型是针对 泛型类型 来说的,因为 反射泛型 会更加复杂一些。在前面的范例中,我们获得了程序集中的所有类型,并循环打印了它们,打印结果仅仅显示出了类型的全名,而我们通常需要关于类型更详细的信息,本节我们就来看看如何进一步查看类型信息。
NOTE:因为一个程序集包含很多类型,一个类型包含很多成员(方法、属性等),一个成员又包含很多其他的信息,所以如果我们从程序集层次开始写代码去获取每个层级的信息,那么会嵌套很多的foreach语句,为了阅读方便,我会去掉最外层的循环。
1.获取基本信息
有了前面Type一节的介绍,我想完成这里应该只是打打字而已,所以我直接写出代码,如有必要,会在注释中加以说明。我们再写一个方法TypeExplore,用于获取类型的详细信息(记得AssemblyExplore只获取了类型的名称):
public static void TypeExplore(Type t) {
StringBuilder sb = new StringBuilder();
sb.Append("名称信息:\n");
sb.Append("Name: " + t.Name + "\n");
sb.Append("FullName: " + t.FullName + "\n");
sb.Append("Namespace: " + t.Namespace + "\n");
sb.Append("\n其他信息:\n");
sb.Append("BaseType(基类型): " + t.BaseType + "\n");
sb.Append("UnderlyingSystemType: " + t.UnderlyingSystemType + "\n");
sb.Append("\n类型信息:\n");
sb.Append("Attributes(TypeAttributes位标记): " + t.Attributes + "\n");
sb.Append("IsValueType(值类型): " + t.IsValueType + "\n");
sb.Append("IsEnum(枚举): " + t.IsEnum + "\n");
sb.Append("IsClass(类): " + t.IsClass + "\n");
sb.Append("IsArray(数组): " + t.IsArray + "\n");
sb.Append("IsInterface(接口): " + t.IsInterface + "\n");
sb.Append("IsPointer(指针): " + t.IsPointer + "\n");
sb.Append("IsSealed(密封): " + t.IsSealed + "\n");
sb.Append("IsPrimitive(基类型): " + t.IsPrimitive + "\n");
sb.Append("IsAbstract(抽象): " + t.IsAbstract + "\n");
sb.Append("IsPublic(公开): " + t.IsPublic + "\n");
sb.Append("IsNotPublic(不公开): " + t.IsNotPublic + "\n");
sb.Append("IsVisible: " + t.IsVisible + "\n");
sb.Append("IsByRef(由引用传递): " + t.IsByRef + "\n");
Console.WriteLine(sb.ToString());
}
然后,我们在Main方法中输入:
Type t = typeof(DemoClass);
TypeExplore(t);
会得到这样的输出:
名称信息:
Name: DemoClass
FullName: Demo.DemoClass
Namespace: Demo
其他信息:
BaseType(基类型): Demo.BaseClass
UnderlyingSystemType: Demo.DemoClass
类型信息:
Attributes(TypeAttributes位标记): AutoLayout, AnsiClass, Class, Public, Sealed,
BeforeFieldInit
IsValueType(值类型): False
IsEnum(枚举): False
IsClass(类): True
IsArray(数组): False
IsInterface(接口): False
IsPointer(指针): False
IsSealed(密封): True
IsPrimitive(基类型): False
IsAbstract(抽象): False
IsPublic(公开): True
IsNotPublic(不公开): False
IsVisible: True
IsByRef(由引用传递): False
值得注意的是Attributes属性,它返回一个TypeAttributes位标记,这个标记标识了类型的一些元信息,可以看到我们熟悉的Class、Public、Sealed。相应的,IsClass、IsSealed、IsPublic等属性也返回为True。
2.成员信息 与 MemberInfo 类型
我们先考虑一下对于一个类型Type,可能会包含什么类型,常见的有字段、属性、方法、构造函数、接口、嵌套类型等。MemberInfo 类代表着 Type的成员类型,值得注意的是Type类本身又继承自MemberInfo类,理解起来并不困难,因为一个类型经常也是另一类型的成员。Type类提供 GetMembers()、GetMember()、FindMember()等方法用于获取某个成员类型。
我们再添加一个方法 MemberExplore(),来查看一个类型的所有成员类型。
public static void MemberExplore(Type t) {
StringBuilder sb = new StringBuilder();
MemberInfo[] memberInfo = t.GetMembers();
sb.Append("查看类型 " + t.Name + "的成员信息:\n");
foreach (MemberInfo mi in memberInfo) {
sb.Append("成员:" + mi.ToString().PadRight(40) + " 类型: " + mi.MemberType + "\n");
}
Console.WriteLine(sb.ToString());
}
然后我们在Main方法中调用一下。
MemberExplore(typeof(DemoClass));
产生的输出如下:
查看类型 DemoClass的成员信息:
--------------------------------------------------
成员:Void add_myEvent(Demo.DemoDelegate) 类型: Method
成员:Void remove_myEvent(Demo.DemoDelegate) 类型: Method
成员:System.String get_Name() 类型: Method
成员:Void set_Name(System.String) 类型: Method
成员:Void SayGreeting(System.String) 类型: Method
成员:System.Type GetType() 类型: Method
成员:System.String ToString() 类型: Method
成员:Boolean Equals(System.Object) 类型: Method
成员:Int32 GetHashCode() 类型: Method
成员:Void .ctor() 类型: Constructor
成员:System.String Name 类型: Property
成员:Demo.DemoDelegate myEvent 类型: Event
成员:System.String text 类型: Field
成员:Demo.DemoClass+NestedClass 类型: NestedType
我们使用了GetMembers()方法获取了成员信息的一个数组,然后遍历了数组,打印了成员的名称和类型。如同我们所知道的:Name属性在编译后成为了get_Name()和set_Name()两个独立的方法;myEvent事件的注册(+=)和取消注册(-=)分别成为了add_myEvent()和remove_myEvent方法。同时,我们发现私有(private)字段name 没有被打印出来,另外,基类System.Object的成员GetType()和Equals()也被打印了出来。
有的时候,我们可能不希望查看基类的成员,也可能希望查看私有的成员,此时可以使用GetMembers()的重载方法,传入BindingFlags 位标记参数来完成。BindingFlags位标记对如何获取成员的方式进行控制(也可以控制如何创建对象实例,后面会说明)。对于本例,如果我们想获取所有的公有、私有、静态、实例 成员,那么只需要这样修改GetMembers()方法就可以了。
MemberInfo[] memberInfo = t.GetMembers(
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly
);
此时的输出如下:
查看类型 DemoClass的成员信息:
--------------------------------------------------
成员:Void add_myEvent(Demo.DemoDelegate) 类型: Method
成员:Void remove_myEvent(Demo.DemoDelegate) 类型: Method
成员:System.String get_Name() 类型: Method
成员:Void set_Name(System.String) 类型: Method
成员:Void SayGreeting(System.String) 类型: Method
成员:Void .ctor() 类型: Constructor
成员:System.String Name 类型: Property
成员:Demo.DemoDelegate myEvent 类型: Event
成员:System.String name 类型: Field
成员:Demo.DemoDelegate myEvent 类型: Field
成员:System.String text 类型: Field
成员:Demo.DemoClass+NestedClass 类型: NestedType
可以看到,继承自基类 System.Object 的方法都被过滤掉了,同时,打印出了私有的 name, myEvent 等字段。
现在如果我们想要获取所有的方法(Method),那么我们可以使用 Type类的FindMembers()方法:
MemberInfo[] memberInfo = t.FindMembers(
MemberTypes.Method, // 说明查找的成员类型为 Method
BindingFlags.Public |
BindingFlags.Static |
BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly,
Type.FilterName,
"*"
);
Type.FilterName 返回一个MemberFilter类型的委托,它说明按照方法名称进行过滤,最后一个参数“*”,说明返回所有名称(如果使用“Get*”,则会返回所有以Get开头的方法)。现在的输出如下:
查看类型 DemoClass的成员信息:
--------------------------------------------------
成员:Void add_myEvent(Demo.DemoDelegate) 类型: Method
成员:Void remove_myEvent(Demo.DemoDelegate) 类型: Method
成员:System.String get_Name() 类型: Method
成员:Void set_Name(System.String) 类型: Method
成员:Void SayGreeting(System.String) 类型: Method
MemberInfo 类有两个属性值得注意,一个是DeclaringType,一个是 ReflectedType,返回的都是Type类型。DeclaredType 返回的是声明该成员的类型。比如说,回顾我们之前的一段代码:
MemberInfo[] members = typeof(DemoClass).GetMembers();
它将返回所有的公有成员,包括继承自基类的Equals()等方法,对于Equals()方法来说,它的 DeclaringType 返回的是相当于 typeof(Object) 的类型实例,因为它是在 System.Object中被定义的;而它的ReflectedType 返回的则是相当于 typeof(DemoClass) 类型实例,因为它是通过 DemoClass 的类型实例被获取的。