Reflection and Attributes in C# (Part 3): Members of Reflective Types

2020年1月5日 76点热度 1人点赞 0条评论
内容目录

In the previous article, we introduced how to obtain the Type type, which is the foundation of reflection.

In this article, we will use Type to obtain member information and print the information obtained through reflection to lay a foundation for subsequent reflection operations.

1. Getting Type Information

We often encounter the terms functions and methods, and many people mix them up.

A method is in the form of public void Test(){};

A function refers to any code block that can be called using a specific name, such as properties, fields, methods, delegates, events, etc.;

As long as a code block can be called (used) by a specific name, it is a function; while a method is a code block composed of return value, name, parameters, etc.;

To operate reflection, the first step is to obtain the reflection information of a type, and the Type of the type is closely related to the following various types.

Type Description
Assembly Load assemblies, read assembly information, get types, etc.
Module Access one or more modules in an assembly
PropertyInfo Property information of a type
FieldInfo Field information of a type
ConstructorInfo Constructor information of a type
MethodInfo Methods of a type
ParameterInfo Parameters of a constructor or method
EventInfo Events of a type
MemberInfo Member information, which inherits all types except for Assembly and Module

1.1 Base Classes and Interfaces of Types

1.1.1 Base Class

In C#, a type can only inherit from one type (base type). Using the instance's Type.BaseType property, you can get the base type of this type.

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

1.1.2 Getting Implemented Interfaces

GetInterface() and GetInterfaces() can be used to obtain the interfaces implemented by a type.

Example

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

Output

  IDisposable
  IAsyncDisposable

1.1.3 Getting Generic Interfaces

              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);

Output

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

Note that if you want to get the interface Type by name, you need to use the name of the generic type, such as IList1`.

1.2 Getting Property and Field Members

1.2.1 Constructors

A type must have a constructor, and even if you do not write a constructor, C# will generate a default constructor at compile time.

GetConstructor() or GetConstructors() can obtain the constructor of type ConstructorInfo;

ConstructorInfo's GetParameter() or GetParameters() can obtain information about the parameters of the constructor;

Create a class

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

Print

              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);
                  }
              }

Output

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

The results above indicate that only public constructors can be retrieved;

For more information on using ConstructorInfo, you can refer here https://docs.microsoft.com/en-us/dotnet/api/system.reflection.constructorinfo?view=netcore-3.1

1.2.2 Properties

You can use GetPropertie() or GetProperties() to obtain one or more properties of the type.

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

Output

  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 Fields

You can use GetField() or GetFields() to obtain one or more fields of the type.

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

Output

  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

Here is a question, are all the retrieved fields public?

Are the fields inside Type all public, or can reflection only retrieve public fields of the type?

Let's verify this through an experiment.

Create a class

      public class MyClass
      {
          public string A { get; set; }
      // non-public property, generally not written like this
      private string B { get; set; }

      public string C;
      protected string D;
      internal string E;
      private string G;
  }</code></pre>

Print

              Type type = typeof(MyClass);
          PropertyInfo[] listA = type.GetProperties();
          // Properties do not have item.IsPublic etc.
          foreach (var item in listA)
              Console.WriteLine(item.Name + "  |  " + item.PropertyType);

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

          IEnumerable<PropertyInfo> 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<FieldInfo> listD = type.GetRuntimeFields();
          foreach (var item in listD)
              Console.WriteLine(item.Name + "  |  " + item.FieldType + "    |   " + item.IsPrivate + "    |   " + item.IsPublic);</code></pre>

Output

  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() and GetFields() can only retrieve public properties/fields;

GetRuntimeProperties() and GetRuntimeFields() can retrieve all properties/fields;

Another important point is that GetRuntimeFields() retrieves <A>k__BackingField and <B>k__BackingField because properties like get;set; automatically generate backing fields in C#.

1.2.4 Methods

You can use GetMethod() or GetMethods() to obtain the MethodInfo of the type, which represents method information;

MethodInfo is very similar to ConstructorInfo, as shown in the example below.

              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("***********");
              }

Output

  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    |
  ... ...

Reference documentation: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodinfo?view=netcore-3.1

1.2.5 Events

You can use GetEvent() or GetEvents() to get the list of events of the type, returning EventInfo / EventInfo[].

Create a type

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

Print

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

Output

  TestHandler   |   Mytest.MyClass+Test

1.2.6 Members

Use GetMember() or GetMembers() to retrieve the members of a type, returning MemberInfo / MemberInfo[] types.

In simple terms, this is an indiscriminate collection of the aforementioned constructors, properties, fields, etc.

Create a type

      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()
      {
      }
  }</code></pre>

Print

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

Output

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

This article is authorized for publication by the "NCC Open Source Community" subscription account.

痴者工良

高级程序员劝退师

文章评论