• 反射学习笔记三(转载)


    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 的类型实例被获取的。

  • 相关阅读:
    swagger,参数,list,swaggerui测试list<string>类型参数示例
    c# 获取路径的方法详解
    The assembly for System.Buffers could not be loaded;无法加载System.Buffers的程序集
    把.net Core 项目迁移到VS2019 for MAC
    Asp.net Core 3.0 Identity 使用smtp账户确认和密码恢复
    Mui使用jquery并且使用点击跳转新窗口
    运行第一个abp项目VS2015+localDB
    Asp.net MVC+Bootstrap3的悬浮式登录框效果
    MVC配置ckeditor+ckfinder
    EF 数据初始化
  • 原文地址:https://www.cnblogs.com/johnwonder/p/1672745.html
Copyright © 2020-2023  润新知