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

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

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

相关文章
|
15天前
|
编译器 C# 开发者
C# 9.0 新特性解析
C# 9.0 是微软在2020年11月随.NET 5.0发布的重大更新,带来了一系列新特性和改进,如记录类型、初始化器增强、顶级语句、模式匹配增强、目标类型的新表达式、属性模式和空值处理操作符等,旨在提升开发效率和代码可读性。本文将详细介绍这些新特性,并提供代码示例和常见问题解答。
33 7
C# 9.0 新特性解析
|
14天前
|
C# 开发者
C# 10.0 新特性解析
C# 10.0 在性能、可读性和开发效率方面进行了多项增强。本文介绍了文件范围的命名空间、记录结构体、只读结构体、局部函数的递归优化、改进的模式匹配和 lambda 表达式等新特性,并通过代码示例帮助理解这些特性。
28 2
|
2月前
|
编译器 C# Android开发
震惊!Uno Platform 与 C# 最新特性的完美融合,你不可不知的跨平台开发秘籍!
Uno Platform 是一个强大的跨平台应用开发框架,支持 Windows、macOS、iOS、Android 和 WebAssembly,采用 C# 和 XAML 进行编程。C# 作为其核心语言,持续推出新特性,如可空引用类型、异步流、记录类型和顶级语句等,极大地提升了开发效率。要在 Uno Platform 中使用最新 C# 特性,需确保开发环境支持相应版本,并正确配置编译器选项。通过示例展示了如何在 Uno Platform 中应用可空引用类型、异步流、记录类型及顶级语句等功能,帮助开发者更好地构建高效、优质的跨平台应用。
208 59
|
24天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
31 3
|
23天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
37 1
|
1月前
|
JSON C# 开发者
C#语言新特性深度剖析:提升你的.NET开发效率
【10月更文挑战第15天】C#语言凭借其强大的功能和易用性深受开发者喜爱。随着.NET平台的演进,C#不断引入新特性,如C# 7.0的模式匹配和C# 8.0的异步流,显著提升了开发效率和代码可维护性。本文将深入探讨这些新特性,助力开发者在.NET开发中更高效地利用它们。
36 1
|
22天前
|
编译器 C#
c# - 运算符<<不能应用于long和long类型的操作数
在C#中,左移运算符的第二个操作数必须是 `int`类型,因此需要将 `long`类型的位移计数显式转换为 `int`类型。这种转换需要注意数据丢失和负值处理的问题。通过本文的详细说明和示例代码,相信可以帮助你在实际开发中正确使用左移运算符。
11 0
|
1月前
|
C#
C# 可空类型(Nullable)
C# 单问号 ? 与 双问号 ??
47 12
|
3月前
|
程序员 C#
C# 语言类型全解
C# 语言类型全解
25 0
|
3月前
|
C# 索引
C#各大版本特性
C#各大版本特性
76 0