上篇文章主要介紹了程序集的內容:程序集和反射(一),時隔這么久,今天終於騰出點時間,把反射部分的知識點給整理一下,不把這個寫完,心里總覺得有點堵。對於反射,我相信很多人跟LZ一個德行,不會,所以不用,不用,所以永遠不會。
通過System.Reflection命名空間中的類已經System.Type,您可以獲取有關已加載的程序集和在其中定義的類型(如類、接口、值類型)的信息。您也可以使用反射在運行時創建類型實例,以及調用和訪問這些實例。
程序集包含模塊,而模塊包含類型,類型又包含成員。 反射則提供了封裝程序集、模塊和類型的對象。 您可以使用反射動態地創建類型的實例,將類型綁定到現有對象,或從現有對象中獲取類型。 然后,可以調用類型的方法或訪問其字段和屬性。
反射通常具有以下用途:
-
類型 作用 Assembly 定義和加載程序集,加載在程序集清單中列出的模塊,以及從此程序集中查找類型並創建該類型的實例。用來獲取程序集內部信息 EventInfo 發現以下信息:事件的名稱、事件處理程序數據類型、自定義特性、聲明類型和反射類型等;並添加或移除事件處理程序。 FieldInfo 發現以下信息:字段的名稱、訪問修飾符(如 public 或 private)和實現詳細信息(如 static)等;並獲取或設置字段值 。該類保存給定的字段信息 MethodInfo 發現以下信息:方法的名稱、返回類型、參數、訪問修飾符(如 public 或 private)和實現詳細信息(如 abstract 或 virtual)等。 使用 Type 的 GetMethods 或 GetMethod 方法來調用特定的方法。該類保存給定的方法信息 MemberInfo 該類是一個基類,它定義了EventInfo、FieldInfo、MethodInfo、PropertyInfo的多個公用行為 Module 發現以下信息:包含模塊的程序集以及模塊中的類等。 您還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法。該類可以使你能訪問多個程序集中的給定模塊 ParameterInfo 發現以下信息:參數的名稱、數據類型、參數是輸入參數還是輸出參數,以及參數在方法簽名中的位置等。該類保存給定的參數信息 PropertyInfo 發現以下信息:屬性的名稱、數據類型、聲明類型、反射類型和只讀或可寫狀態等;並獲取或設置屬性值。該類保存給定的屬性信息 - 使用 ConstructorInfo 發現以下信息:構造函數的名稱、參數、訪問修飾符(如 public 或 private)和實現詳細信息(如 abstract 或 virtual)等。 使用 Type 的 GetConstructors 或 GetConstructor 方法來調用特定的構造函數。(以上內容參考MSDN)
Type類
表示類型聲明:類類型、接口類型、數組類型、值類型、枚舉類型、類型參數、泛型類型定義,以及開放或封閉構造的泛型類型。
可以通過以下兩種方式獲得Type:
1.通過類獲得Type: Type t=typeof(Person);
2.通過對象獲得Type:Person p=new Person(); Type t=p.GetType();
這里仍然采用上篇文章中的示例:
1 static void Main(string[] args) 2 { 3 //通過反射動態調用另一個程序集中的方法 4 //1加載程序集 5 string path = AppDomain.CurrentDomain.BaseDirectory;//獲取當前.exe執行文件的路徑 6 path = Path.Combine(path, "MyAssembly.dll");//拼接程序集的路徑 7 Assembly assembly = Assembly.LoadFile(path); 8 //2創建Person類的對象 9 Type type = assembly.GetType("MyAssembly.Person"); 10 object o = Activator.CreateInstance(type,"wolf",22,"未知");//實例化 11 //3獲取方法的類型 12 MethodInfo methodInfo = type.GetMethod("SayHi"); 13 //4反射調用方法 14 methodInfo.Invoke(o, null); 15 Console.Read(); 16 }
調用Assembly的GetExportedTypes方法可以得到Assembly中定義的所有的public類型。
調用Assembly的GetTypes()方法可以得到Assembly中定義的所有的類型。
調用Assembly的GetType(name)方法可以得到Assembly中定義的全名為name的類型信息。如: Type type = assembly.GetType("MyAssembly.Person");
動態創建對像
Activator.CreateInstance(Type t)會動態調用類的無參構造函數創建一個對象,返回值就是創建的對象,如果類沒有無參構造函數就會報錯。
GetConstructor(參數列表);//這個是找到帶參數的構造函數。例如:object o = Activator.CreateInstance(type,"wolf",22,"未知");//實例化
Type類的方法
bool IsAssignableFrom(Type c):判斷當前的類型的變量是不是可以接受c類型變量的賦值。
1 Type type = assembly.GetType("MyAssembly.Person"); 2 Type studentType = assembly.GetType("MyAssembly.Student"); 3 Console.WriteLine(type.IsAssignableFrom(studentType));
Result:True 因為Person p=new Student();
typeof(IPlugin).IsAssignableFrom(t)
bool IsInstanceOfType(object o):判斷對象o是否是當前類的實例(當前類可以是o的類、父類、接口)
Person p = new Student(); //判斷p是否是一個Student類的實例 bool r = typeof(Student).IsInstanceOfType(p);//True
bool IsSubclassOf(Type c):判斷當前類是否是類c的子類。實用於類,不適用於接口
//判斷Student是否是Person的子類 bool r = typeof(Student).IsSubclassOf(typeof(Person));//Tru
IsAbstract,判斷是否為抽象的,含接口
//判斷Person是否是抽象類或接口 bool r = typeof(Person).IsAbstract;//False
動態調用成員
MemberInfo類 抽象類,有很多子類,下面講的類都繼承自它,獲取程序集成員的相關信息(類型、方法、事件、字段和屬性)
PropertyInfo 獲取屬性
主要成員:CanRead、CanWrite、PropertyType屬性類型;SetValue、GetValue:讀取值,設置值,第一個參數是實例對象,因為set、get要針對具體實例,最后一個參數null。pInfo.SetValue(p1, 30, null)
MethodInfo 獲取方法
MethodInfo 都是和具體對象不相關的,所以需要第一個參數指定要執行的對象。
//3獲取方法的類型 MethodInfo methodInfo = type.GetMethod("SayHi");
FieldInfo 獲取字段
EventInfo 獲取事件
案例:

<?xml version="1.0" encoding="utf-8" ?> <Persons> <person> <Name>wolfy1</Name> <Age>22</Age> <Gender>男</Gender> </person> <person> <Name>wolfy2</Name> <Age>23</Age> <Gender>女</Gender> </person> <person> <Name>wolfy3</Name> <Age>24</Age> <Gender>未知</Gender> </person> </Persons>
控制台程序測試程序:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.IO; 6 using System.Reflection; 7 using System.Xml; 8 using System.Xml.Linq; 9 namespace AssemblyDemo 10 { 11 class Program 12 { 13 14 static void Main(string[] args) 15 { 16 //通過反射動態調用另一個程序集中的方法 17 //1加載程序集 18 string path = AppDomain.CurrentDomain.BaseDirectory;//獲取當前.exe執行文件的路徑 19 string xmlPath = Path.Combine(path, "Person.xml"); 20 path = Path.Combine(path, "MyAssembly.dll");//拼接程序集的路徑 21 XElement xml; 22 Assembly assembly = Assembly.LoadFile(path); 23 xml = XElement.Load(xmlPath); 24 //2創建Person類的對象 25 Type type = assembly.GetType("MyAssembly.Person"); 26 foreach (var item in xml.Elements("person")) 27 { 28 PropertyInfo[] properties = type.GetProperties(); 29 foreach (PropertyInfo p in properties) 30 { 31 Console.Write(item.Element(p.Name).Value+"\t"); 32 } 33 Console.WriteLine(); 34 } 35 Console.Read(); 36 } 37 } 38 }
結果:
結語:
關於程序集和反射的基礎,就介紹到這里,怎么樣去掌握,還得勤思考,多用才行。