主要介紹什麼是.NET反射特性,.NET反射能為我們做些什麼,最後介紹幾種常用的反射的實現方法,通過對反射性特的瞭解,可以設計出非常有用的基於反射的編程模式。
[.net 面向對象程式設計進階] (20) 反射(Reflection) 利用反射技術實現動態編程(上)
本節導讀:本節主要介紹什麼是.NET反射特性,.NET反射能為我們做些什麼,最後介紹幾種常用的反射的實現方法,通過對反射性特的瞭解,可以設計出非常有用的基於反射的編程模式。
讀前必備:
[.net 面向對象編程基礎] (10) 類的成員(欄位、屬性、方法)
1.什麼是.NET反射?
反射是.NET一個重要的特性,《CLR via C#》一書中對.NET反射的解釋為:在我們應用程式中使用元數據來表示存儲。編譯程式集或模塊時,編譯器會創建一個類型定義表、一個欄位定義表、一個方法定義表以及其它表。而我們如果想動態調用這些元數據表(或說是解析這些表),或說是為這些元數據創建一個對象模型,這個過程就是反射。
簡單通俗的說,就是動態調用編譯過的程式集中的屬性,欄位,方法等的過程,就是反射。
反射在.NET,通過System.Reflection命名空間中的類來實現。
2.反射能為我們做些什麼?
這個問題是我們學習反射的重點,總得知道學習它的好處,才會繼續把本文看下去。
反射特性,確實是.NET一個非常重要且有用的特性。
A.枚舉類型成員
B.實例化新對象
C.執行對象成員
D.查找類型信息
E.查詢程式集信息
F.檢查應用於某種類型的自定義特性
G.創建和編譯新的程式集
H.簡化執行時而非編譯時綁定的數據的操作。(C# 4.0以後新功能)
此外.NET新版本中允許泛型上的反射.
以上是反射的基本特性,參考了《C#本質論》和《C#高級編程》
基於上面的基本特性,我們可以設計出很多非常實用的編程模式。
下麵列舉幾種基於反射設計模式下的實例:
A.利用反射創動態創建程式集的API文檔。基於反射允許枚舉程式集中類型及成員的特性,我們可以通過反射獲取已編譯的程式集中的欄位方法屬性事件和他們的XML註釋。從而動態創建程式集的API文檔;
B.非常常用的反射工廠模式。反射工廠模式在設計模式中比較容易理解,也比較簡單。很多代碼生成器中就利用這種設計模式完成不同資料庫的反射調用。比如我們有MsSql、MySql、Oracle這三種資料庫,在項目設計中,我們有可能隨時換另一種資料庫(當然這隻是假設),因此需要同時實現這三種資料庫的基礎增刪改查的類即數據訪問類。我們要切換資料庫的時候,只需要在config中更改資料庫類型,其他的工作交給反射工廠類去動態調用編譯好的程式集中對應的資料庫訪問方法。
如果沒有理解也沒關係,這裡只是說明一下反射的應用實例,以便於更有信心的學習反射。反射在設計模式中的應還有很多,這裡不再列舉。
3.反射應用基礎
上面說了這麼多,無非就是先讓我們理解反射能為我們做些什麼,下麵進入正題,說一下反射的代碼實現。
下麵主要介紹反射的核心類及類成員
反射的命名空間:System.Reflection
反射的類大多都在這個命名空間中。
主要的類: System.Type
這個類是反射的核心,其屬性方法可以得到運行時的信息。
Type類派生於System.Reflection.MemberInfo抽象類
MemberInfo類中的只讀屬性 |
||
屬性 |
描述 |
備註 |
Type DeclaringType |
獲取聲明該成員的類或介面的類型 |
|
MemberTypes MemberType |
獲取成員的類型,這個值用於指示該成員是欄位、方法、屬性、事件、或構造函數 |
這是一個枚舉,它定義了用於表示不同成員的類型值。這些值包括:MemberTypes.Constructor, MemberTypes.Method, MemberTypes.Field, MemberTypes.Event, MemberTypes.Property。因此可以通過檢查MemberType屬性來確定成員的類型,例如,在MemberType屬性的值為MemberTypes.Method時,該成員為方法 |
Int MetadataToken |
獲取與特定元數據相關的值 |
|
Module Module |
獲取一個代表反射類型所在模塊(可執行文件)的Module對象 |
|
String Name |
成員的名稱 |
|
Type ReflectedType |
反射的對象類型 |
|
Type類的只讀屬性 |
|
屬性 |
描述 |
Assembly Assembly |
獲取指定類型的程式集 |
TypeAttributes Attributes |
獲取制定類型的特性 |
Type BaseType |
獲取指定類型的直接基類型 |
String FullName |
獲取指定類型的全名 |
bool IsAbstract |
如果指定類型是抽象類型,返回true |
bool IsClass |
如果指定類型是類,返回true |
string Namespace |
獲取指定類型的命名空間 |
Type類的方法 |
|
方法 |
描述 |
ConstructorInfo[] GetConstructors() |
獲取指定類型的構造函數列表 |
EventInfo[] GetEvents(); |
獲取指定類型的時間列 |
FieldInfo[] GetFields(); |
獲取指定類型的欄位列 |
Type[] GetGenericArguments(); |
獲取與已構造的泛型類型綁定的類型參數列表,如果指定類型的泛型類型定義,則獲得類型形參。對於正早構造的類型,該列表就可能同時包含類型實參和類型形 |
MethodInfo[] GetMethods(); |
獲取指定類型的方法列表 |
PropertyInfo[] GetProperties(); |
獲取指定類型的屬性列表e |
MemberInfo[] GetMembers(); |
獲取指定類型的成員列表 |
反射還有很多類,這裡不一一介紹,詳細可以查閱MSDN:
https://msdn.microsoft.com/zh-cn/library/system.reflection.aspx
4.反射實例
下麵通過一個實例來學習一下反射最基本的使用方法。
建立一個解決方案,包含兩個項目,項目ClassLibrary生成一個DLL(包含兩個類),另一個項目是ReflectionTestGet,用於反射調用類ClassLibrary
第一個項目的兩個類如下:
MartialArtsMaster.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ClassLibrary { /// <summary> /// 類:武林高手 /// MartialArtsMaster /// </summary> class MartialArtsMaster { /// <summary> /// 級別 /// </summary> public int _level = 9; /// <summary> /// 編號 /// </summary> public int Id { get; set; } /// <summary> /// 姓名 /// </summary> public string Name { get; set; } /// <summary> /// 年齡 /// </summary> public int Age { get; set; } /// <summary> /// 門派 /// </summary> public string Menpai { get; set; } /// <summary> /// 武學 /// </summary> public string Kungfu { get; set; } /// <summary> /// 級別 /// </summary> public int Level { get { return _level; } set { _level = value; } } /// <summary> /// 攻擊 /// </summary> /// <param name="kungfu"></param> /// <returns></returns> public string Attack(string kungfu) { return "使用用了功夫:" + kungfu; } public string Kill(string kungfu, string name) { return "使用用了功夫:" + kungfu + "擊殺了" + name; } } }View Code
Person.cs
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace ClassLibrary { /// <summary> /// 類:人 /// </summary> class Person { public string gender { get; set; } public string race { get; set; } public string Country { get; set; } public string Eat(string strCountry) { switch (strCountry) { case "美國": return "愛吃西餐"; case "南韓": return "愛吃泡菜"; default: return "不知道"; } } } }View Code
第二個項目調用如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Reflection; namespace ReflectionTestGet { class Program { static void Main(string[] args) { Assembly asm = Assembly.LoadFrom("ClassLibrary.dll"); //載入指定的程式集 Type[] alltype = asm.GetTypes(); //獲取程式集中的所有類型列表 foreach (Type calssName in alltype) { Console.WriteLine("載入程式的集類名:"+ calssName.Name); //列印出程式集所有類 foreach (var field in calssName.GetFields()) Console.WriteLine(calssName.Name+"欄位有:" + field.Name); //列印出程式集所有欄位,註意只能獲取公有欄位 foreach (var pro in calssName.GetProperties()) Console.WriteLine(calssName.Name + "屬性有:" + pro.Name); //列印出程式集所有屬性 foreach (var met in calssName.GetMethods()) Console.WriteLine(calssName.Name + "方法有:" + met.Name); //列印出程式集所有方法 } Console.ReadKey(); } } }View Code
運行結果如下:
5.本節要點:
本節主要介紹和反射的用途及反射的基本操作類及屬性方法,下節繼續深入介紹如何將反射技術應用於實際項目之中。
==============================================================================================
<如果對你有幫助,記得點一下推薦哦,如有
有不明白或錯誤之處,請多交流>
<對本系列文章閱讀有困難的朋友,請先看《.net 面向對象編程基礎》>
<轉載聲明:技術需要共用精神,歡迎轉載本博客中的文章,但請註明版權及URL>
==============================================================================================