上一篇文章中,介绍如何获取 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<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 ,表示方法信息;

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 开源社区》订阅号发布

C#反射与特性(三):反射类型的成员的更多相关文章

  1. C#反射与特性(五):类型成员操作

    目录 1,MemberInfo 1.1 练习-获取类型的成员以及输出信息 1.2 MemberType 枚举 1.3 MemberInfo 获取成员方法并且调用 1.4 获取继承中方法的信息(Decl ...

  2. C#4.0图解教程 - 第24章 反射和特性 - 1.反射

    24.1 元数据和反射 有关程序及类型的数据被成为 元数据.他们保存在程序集中. 程序运行时,可以查看其他程序集或其本身的元数据.一个运行的程序查看本身元数据或其他程序的元数据的行为叫做 反射. 24 ...

  3. C#反射与特性(七):自定义特性以及应用

    目录 1,属性字段的赋值和读值 2,自定义特性和特性查找 2.1 特性规范和自定义特性 2.2 检索特性 3,设计一个数据验证工具 3.1 定义抽象验证特性类 3.2 实现多个自定义验证特性 3.3 ...

  4. C#反射与特性(六):设计一个仿ASP.NETCore依赖注入Web

    目录 1,编写依赖注入框架 1.1 路由索引 1.2 依赖实例化 1.3 实例化类型.依赖注入.调用方法 2,编写控制器和参数类型 2.1 编写类型 2.2 实现控制器 3,实现低配山寨 ASP.NE ...

  5. 详解C#特性和反射(三)

    类型信息(Type Information)用来表示类型声明的信息,通过抽象基类System.Type的实例存储这些信息,当使用反射时,CLR获取指定类型的Type对象,通过这个对象即可访问该类型的任 ...

  6. C#反射与特性(四):实例化类型

    目录 1,实例化类型 1.1 Activator.CreateInstance() 1.2 ConstructorInfo.Invoke() 2,实例化委托 3,实例化泛型类型 3.1 实例化泛型 3 ...

  7. .NET基础拾遗(4)委托、事件、反射与特性

    Index : (1)类型语法.内存管理和垃圾回收基础 (2)面向对象的实现和异常的处理基础 (3)字符串.集合与流 (4)委托.事件.反射与特性 (5)多线程开发基础 (6)ADO.NET与数据库开 ...

  8. 十七、C# 反射、特性和动态编程

    反射.特性和动态编程   1.访问元数据 2.成员调用 3.泛型上的反射 4.自定义特性 5.特性构造器 6.具名参数 7.预定义特性 8.动态编程   特性(attribute)是在一个程序集中插入 ...

  9. C#特性和反射

    C#特性和反射 .NET编译器的任务之一就是为所有定义和引用的类型生成元数据描述.除了程序集中标准的元数据外,.NET平台还支持特定(attribute)把更多的元数据嵌入到程序集中. .NET特性扩 ...

随机推荐

  1. oracle函数 CONCAT(c1,c2)

    [功能]连接两个字符串 [参数]c1,c2 字符型表达式 [返回]字符型 同:c1||c2 [示例] select concat('010-','88888888')||'转23' 高乾竞电话 fro ...

  2. Python基础10 回顾

    从最初的"Hello World",走到面向对象,该回过头来看看,教程中是否遗漏了什么. 我们之前提到一句话,"Everything is Object".那么 ...

  3. AtCoder Beginner Contest 075 C Bridge(割边)

    求割边个数.Tarjan的板子.. #include <bits/stdc++.h> using namespace std; const int MAXN = 55; const int ...

  4. 2018-8-10-WPF-使用-VisualStudio-2017-项目文件

    title author date CreateTime categories WPF 使用 VisualStudio 2017 项目文件 lindexi 2018-08-10 19:16:53 +0 ...

  5. Educational Codeforces Round 12 B C题、

    B. Shopping 题意:n个顾客,每个顾客要买m个物品,商场总共有k个物品,看hint就只知道pos(x)怎么算了,对于每一个Aij在k个物品中找到Aij的位置.然后加上这个位置对于的数值,然后 ...

  6. springmvc url处理映射的三种方式:

    一.SpringMVC简介 SpringMVC是一种基于Spring实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,使用了MVC架构模式的思想,将web层进行职责解耦,并管理应用所需对象 ...

  7. 洛谷P1595 信封问题 题解 错排问题

    作者:zifeiy 标签:排列组合,错排问题 题目链接:https://www.luogu.org/problem/P1595 题目描述:某人写了n封信和n个信封,如果所有的信都装错了信封.求所有信都 ...

  8. 买房的贷款时间是否是越长越好?https://www.zhihu.com/question/20842791

    买房的贷款时间是否是越长越好?https://www.zhihu.com/question/20842791

  9. C# AddRange 添加位置

    有没人想知道, AddRange 添加位置 是哪? 是添加到数组的开始,还是数组的末尾? 假如有一个 代码,看起来是下面的,很简单,把一个 list b 放进list a List<int> ...

  10. H3C RIP路由表的更新