C# 反射类型的成员

175 阅读3分钟

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 类型;

ConstructorInfo 的 GetParameter() 或 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 的使用方法,可以参考这里 docs.microsoft.com/zh-cn/dotne…

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

输出

A  |  System.String
**************
A  |  System.String
B  |  System.String
**************
C  |  System.String    |   False    |   True
**************
<A>k__BackingField  |  System.String    |   True    |   False
<B>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 ,表示方法信息;

MethodInfo 跟 ConstructorInfo 非常相似,示例如下

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

参考资料地址:docs.microsoft.com/zh-cn/dotne…

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

原文地址:reflect.whuanle.cn/3.to3.html