zoukankan      html  css  js  c++  java
  • 反射学习笔记三(转载)

    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=1.0.0.0, Culture=neutral, PublicKeyToken=null
    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 的类型实例被获取的。

  • 相关阅读:
    给出两个 非空 的链表用来表示两个非负的整数。其中,它们各自的位数是按照 逆序 的方式存储的,并且它们的每个节点只能存储 一位 数字。
    11
    实战 迁移学习 VGG19、ResNet50、InceptionV3 实践 猫狗大战 问题
    tx2系统备份与恢复
    如何在Ubuntu 18.04上安装和卸载TeamViewer
    bzoj 3732 Network (kruskal重构树)
    bzoj2152 聪聪可可 (树形dp)
    牛客 216D 消消乐 (二分图最小点覆盖)
    牛客 197E 01串
    Wannafly挑战赛23
  • 原文地址:https://www.cnblogs.com/johnwonder/p/1672745.html
Copyright © 2011-2022 走看看