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 ,需要使用 泛型類別的名稱,例如 IList
1`。
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
的使用方法,可以參考這裡 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 ,表示方法資訊;
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 |
... ...
參考資料地址: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