C#反射与特性(三):反射类型的成员

内容纲要

上一篇文章中,介绍如何获取 Type 类型,Type 类型是反射的基础。

本篇文章中,将使用 Type 去获取成员信息,通过打印出反射获取到的信息,为后续操作反射打好基础。

1,获取类型的信息

我们常常可以看到 函数、方法这两个词,很多人对此进行了混用。

方法,就是 public void Test(){} 这样的形式;

函数,指具有确定命名的、并且可以通过名称调用的代码,属性、字段、方法、委托、事件等;

只要能够通过确定的名称调用(使用)的代码块,就是函数;而方法就是 返回值、名称、参数等组成的代码块;

要操作反射,首先要获取到 类型 的反射信息,而类型的 Type ,与以下多种类型密切相关。

类型 说明
Assembly 加载程序集、读取程序集信息、获取类型等
Module 访问程序集中的一个或多个模块
PropertyInfo 类型的属性信息
FieldInfo 类型的字段信息
ConstructorInfo 类型的构造函数信息
MethodInfo 类型的方法
ParameterInfo 构造函数或方法的参数
EventInfo 类型的事件
MemberInfo 成员信息,集成以上除 Assembly、Module 外所有的类型

1.1 类型的基类和接口

1.1.1 基类

C# 中,一个类型只能继承一个类型(基类型),使用实例Type.BaseType 属性,可以获取到此类型的基类型。

              Type type = typeof(MyClass);
              Type baseType = type.BaseType;

1.1.2 获取实现的接口

GetInterface()GetInterfaces() 可以获取类型实现的接口。

示例

              Type type = typeof(System.IO.FileStream);
              Type[] list = type.GetInterfaces();
              foreach (var item in list)
                  Console.WriteLine(item.Name);

输出

  IDisposable
  IAsyncDisposable

1.1.3 获取泛型接口

              Type type = typeof(List<>);
              Type one = type.GetInterface("IList`1");
              Console.WriteLine(one.Name);
              Console.WriteLine("***************");
              Type[] list = type.GetInterfaces();
              foreach (var item in list)
                  Console.WriteLine(item.Name);

输出

  IList`1
  ***************
  IList`1
  ICollection`1
  IEnumerable`1
  IEnumerable
  IList
  ICollection
  IReadOnlyList`1
  IReadOnlyCollection`1

注意的是,如果要通过名称获取接口 Type ,需要使用 泛型类别的名称,例如 IList1`。

1.2 获取属性、字段成员

1.2.1 构造函数

一个类型最少不了的就是构造函数,即使没有编写构造函数,C# 编译时也会生成默认的构造函数。

GetConstructor()GetConstructors() 可以获取构造函数 ConstructorInfo 类型;

ConstructorInfoGetParameter()GetParameters() 可以获取构造函数的参数信息;

创建一个类

      public class MyClass
      {
          static MyClass() { }
          public MyClass() { }
          private MyClass(string a) { }
          public MyClass(int a) { }
      }

打印

              Type type = typeof(MyClass);
              ConstructorInfo[] list = type.GetConstructors();
              foreach (var item in list)
              {
                  Console.WriteLine(item.Name + "   |   " + item.IsStatic + "   |   " + item.IsPublic);
                  ParameterInfo[] parms = item.GetParameters();
                  foreach (var itemNode in parms)
                  {
                      Console.WriteLine(itemNode.Name + "   |   " + itemNode.ParameterType + "    |   " + itemNode.DefaultValue);
                  }
              }

输出

  .ctor   |   False   |   True
  .ctor   |   False   |   True
  a   |   System.Int32    |

上面结果说明了,只能获取 Public 的构造函数;

关于 ConstructorInfo 的使用方法,可以参考这里 https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.constructorinfo?view=netcore-3.1

1.2.2 属性

使用 GetPropertie()GetProperties() 可以获取 类型 的一个或多个属性。

              Type type = typeof(Type);
              PropertyInfo[] list = type.GetProperties();
              foreach (var item in list)
                  Console.WriteLine(item.Name + "   |   " + item.PropertyType);

输出

  IsInterface  |  System.Boolean
  MemberType  |  System.Reflection.MemberTypes
  Namespace  |  System.String
  AssemblyQualifiedName  |  System.String
  FullName  |  System.String
  Assembly  |  System.Reflection.Assembly
  Module  |  System.Reflection.M

1.2.3 字段

使用 GetField()GetFields() 可以获取类型的一个或多个字段。

              Type type = typeof(Type);
              FieldInfo[] list = type.GetFields();
              foreach (var item in list)
                  Console.WriteLine(item.Name + "  |  " + item.FieldType + "    |   " + item.IsPublic);

输出

  Delimiter  |  System.Char    |   True
  EmptyTypes  |  System.Type[]    |   True
  Missing  |  System.Object    |   True
  FilterAttribute  |  System.Reflection.MemberFilter    |   True
  FilterName  |  System.Reflection.MemberFilter    |   True
  FilterNameIgnoreCase  |  System.Reflection.MemberFilter    |   True

这里有个问题,获取到的所有字段,都是 Public 的?

到底是 Type 里面的字段都是 Public 的,还是反射只能获取到类型 Public 字段?

我们通过实验验证一下。

创建一个类

      public class MyClass
      {
          public string A { get; set; }

          // 不公开的属性,一般不会这样写
          private string B { get; set; }

          public string C;
          protected string D;
          internal string E;
          private string G;
      }

打印

              Type type = typeof(MyClass);

              PropertyInfo[] listA = type.GetProperties();
              // 属性没有 item.IsPublic 等
              foreach (var item in listA)
                  Console.WriteLine(item.Name + "  |  " + item.PropertyType);

              Console.WriteLine("**************");

              IEnumerable listB = type.GetRuntimeProperties();
              foreach (var item in listB)
                  Console.WriteLine(item.Name + "  |  " + item.PropertyType);

              Console.WriteLine("**************");

              FieldInfo[] listC = type.GetFields();
              foreach (var item in listC)
                  Console.WriteLine(item.Name + "  |  " + item.FieldType + "    |   " + item.IsPrivate + "    |   " + item.IsPublic);

              Console.WriteLine("**************");

              IEnumerable listD = type.GetRuntimeFields();
              foreach (var item in listD)
                  Console.WriteLine(item.Name + "  |  " + item.FieldType + "    |   " + item.IsPrivate + "    |   " + item.IsPublic);

输出

  A  |  System.String
  **************
  A  |  System.String
  B  |  System.String
  **************
  C  |  System.String    |   False    |   True
  **************
  k__BackingField  |  System.String    |   True    |   False
  k__BackingField  |  System.String    |   True    |   False
  C  |  System.String    |   False    |   True
  D  |  System.String    |   False    |   False
  E  |  System.String    |   False    |   False
  G  |  System.String    |   True    |   False

GetProperties()GetFields() 都只能获取到 public 类型的属性/字段;

GetRuntimeProperties()GetRuntimeFields() ,能够获取所有的属性/字段;

还有一个重要的地方,GetRuntimeFields() 获取到了 <A>k__BackingField<B>k__BackingField,这是因为 get;set;这样的属性,C# 会默认生成一个字段给他。

1.2.4 方法

通过 GetMethod()GetMethods() 可以获取到类型的 MethodInfo ,表示方法信息;

MethodInfoConstructorInfo 非常相似,示例如下

              Type type = typeof(System.IO.File);
              MethodInfo[] list = type.GetMethods();
              foreach (var item in list)
              {
                  Console.WriteLine(item.Name + "   |   " + item.IsStatic + "   |   " + item.IsPublic);
                  ParameterInfo[] parms = item.GetParameters();
                  foreach (var itemNode in parms)
                  {
                      Console.WriteLine(itemNode.Name + "   |   " + itemNode.ParameterType + "    |   " + itemNode.DefaultValue);
                  }
                  Console.WriteLine("***********");
              }

输出

  OpenText   |   True   |   True
  path   |   System.String    |
  ***********
  CreateText   |   True   |   True
  path   |   System.String    |
  ***********
  AppendText   |   True   |   True
  path   |   System.String    |
  ***********
  Copy   |   True   |   True
  sourceFileName   |   System.String    |
  destFileName   |   System.String    |
  ... ...

参考资料地址:https://docs.microsoft.com/zh-cn/dotnet/api/system.reflection.methodinfo?view=netcore-3.1

1.2.5 事件

使用 GetEvent()GetEvents() 可以获取类型的事件列表,返回 EventInfo / EventInfo[] 类型。

创建一个类型

      public class MyClass
      {
          public delegate void Test(int a,int b);
          public event Test TestHandler;
      }

打印

              Type type = typeof(MyClass);
              EventInfo[] list = type.GetEvents();
              foreach (var item in list)
              {
                  Console.WriteLine(item.Name + "   |   " + item.EventHandlerType);
              }

输出

  TestHandler   |   Mytest.MyClass+Test

1.2.6 成员

使用 GetMember()GetMembers() 获取类型的成员,返回 MemberInfo / MemberInfo[] 类型。

简单来说,就是以上构造函数、属性、字段等的无差别集合体。

创建一个类型

      public class MyClass
      {
          public delegate void Test(int a, int b);
          public event Test TestHandler;

          public MyClass(int a) { }

          public MyClass(int a, int b) { }

          public void TestMetod()
          {
          }
      }

打印

              Type type = typeof(MyClass);
              MemberInfo[] list = type.GetMembers();
              foreach (var item in list)
              {
                  Console.WriteLine(item.Name + "   |   " + item.MemberType);
              }

输出

  add_TestHandler   |   Method
  remove_TestHandler   |   Method
  TestMetod   |   Method
  GetType   |   Method
  ToString   |   Method
  Equals   |   Method
  GetHashCode   |   Method
  .ctor   |   Constructor
  .ctor   |   Constructor
  TestHandler   |   Event
  Test   |   NestedType

此文仅授权《NCC 开源社区》订阅号发布

点赞

发表评论

电子邮件地址不会被公开。 必填项已用*标注