1. 程式人生 > >C#反射與特性(三):反射型別的成員

C#反射與特性(三):反射型別的成員

目錄

  • 1,獲取型別的資訊
    • 1.1 型別的基類和介面
    • 1.2 獲取屬性、欄位成員

上一篇文章中,介紹如何獲取 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