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<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 開源社區》訂閱號發布


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM