朋友炒股兩個月賺了10萬,我幫他推廣一下公眾號,把錢用來投資總比放銀行連通貨膨脹都跑不過里強, 硬核離職,在家炒股 ,這是他每天的日志,有些經驗是花錢也買不到的。
一、什么是反射
MSND:反射提供了封裝程序集、模塊和類型的對象(Type 類型)。可以使用反射動態創建類型的實例,將類型綁定到現有對象,或從現有對象獲取類型並調用其方法或訪問其字段和屬性。如果代碼中使用了屬性,可以利用反射對它們進行訪問。
實用概念:反射是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為反射。
反射的名稱空間:System.Reflection,具體參考 http://msdn.microsoft.com/zh-cn/library/system.reflection.aspx
二、利用反射動態創建類的實例
前置條件:我們創建兩個項目來展示反射的簡單應用
- CSharp.Model:類庫,Employee.cs,我們要反射的測試實體類。
- CSharp.Reflection:控制台應用程序項目,Program.cs為主程序類,App.config配置文件,配置我們要反射的程序集的名稱,Constant.cs用於調用配置文件的常量類。
CSharp.Model.Employee代碼如下:
1 /* 2 * 3 * 創建人:李林峰 4 * 5 * 時 間:2012-7-23 6 * 7 * 描 述:反射類的實例 8 * 9 */ 10 11 using System; 12 using System.Collections.Generic; 13 using System.Text; 14 15 namespace CSharp.Model 16 { 17 /// <summary> 18 /// 員工類 19 /// </summary> 20 public class Employee 21 { 22 public int ID { get; set; } //編號 23 public string Name { get; set; } //姓名 24 public string Password { get; set; } //密碼 25 public string Department { get; set; } //部門 26 public string Position { get; set; } //職位 27 28 /// <summary> 29 /// 測試方法 30 /// </summary> 31 /// <returns></returns> 32 public string Method() 33 { 34 return this.ID.ToString(); 35 } 36 } 37 }
CSharp.Reflection的配置文件與常量類代碼如下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <appSettings> 4 <!--程序集名稱--> 5 <add key="AssemblyName" value="CSharp.Model"></add> 6 </appSettings> 7 </configuration> 8 9 10 11 /* 12 * 13 * 創建人:李林峰 14 * 15 * 時 間:2012-7-23 16 * 17 * 描 述:常量類 18 * 19 */ 20 21 using System.Configuration; 22 23 namespace CSharp.Reflection 24 { 25 class Constant 26 { 27 /// <summary> 28 /// 程序集名稱 29 /// </summary> 30 public static string ASSEMBLYNAME = ConfigurationManager.AppSettings["AssemblyName"]; 31 } 32 }
CSharp.Reflection的主程序類代碼如下:
1 /* 2 * 3 * 創建人:李林峰 4 * 5 * 時 間:2012-7-23 6 * 7 * 描 述:應用程序入口 8 * 9 */ 10 11 using System.Reflection;//反射的名稱空間 12 using CSharp.Model; //實體名稱空間 13 14 namespace CSharp.Reflection 15 { 16 class Program 17 { 18 static void Main(string[] args) 19 { 20 Employee employee = (Employee)Assembly.Load(Constant.ASSEMBLYNAME).CreateInstance("CSharp.Model.Employee"); 21 employee.ID = 1; 22 employee.Name = "李林峰"; 23 employee.Department = "技術"; 24 employee.Position = "程序員"; 25 System.Console.WriteLine(employee.Name); 26 System.Console.WriteLine(employee.Department); 27 System.Console.WriteLine(employee.Position); 28 System.Console.WriteLine(employee.Method()); 29 30 System.Console.WriteLine("---------------------------------"); 31 32 Employee employeeNew = (Employee)Assembly.LoadFile(@"E:\公司內網\HZYT.Test\06 C#映射教程\ClassThree\CSharp.Reflection\bin\Debug\CSharp.Model.dll").CreateInstance("CSharp.Model.Employee"); 33 employee.ID = 2; 34 employeeNew.Name = "李林峰"; 35 employeeNew.Department = "技術"; 36 employeeNew.Position = "程序員"; 37 System.Console.WriteLine(employeeNew.Name); 38 System.Console.WriteLine(employeeNew.Department); 39 System.Console.WriteLine(employeeNew.Position); 40 System.Console.WriteLine(employee.Method()); 41 } 42 } 43 }
通過上面的示例可以看出,平時我們在創建對象的時候是通過 Employee employee = new Employee(); 來創建。而應用了反射后,我們通過方法System.Reflection.Assembly.Load("程序集名稱").CreateInstance("類型名稱");在運行時動態的創建類的實例。
上面的實例中我用了兩個方法,主要是強調下反射中Load的是程序集,如上示例employee的實例創建,實際上反射的是已經被我們編譯好的,存在於bin目錄下的CSharp.Model.dll。而employeeNew我們用的方法是LoadFile,其實原理是一樣的,只不過這個方法我們提供的是物理地址。
CreateInstance("類型名稱")中的"類型名稱"一定要為類的全名,即:"名稱空間"+"類名"。
反射出來的為Object對象,我們在使用的時候要進行類型轉換,如上例所示(Employee)Assembly.Load......
運行效果如下圖所示:
三、利用反射動創建類
動態創建類:通過字符串描述類的結構,然后由.net編輯器編輯成類文件,如有必要還可以編輯成.dll的一個動態使用類的過程。
首先我們先進行類的描述,在很多框架中XML是類描述的主要文件類型,這里我們也不例外,為了簡單起見我在本例中用了App.config文件來描述類。
前置條件:
- CSharp.Dynamic:控制台應用程序,Program.cs為主程序類,App.config用於描述類的結構,Constant.cs讀取配置文件的常量類。
CSharp.Dynamic的配置文件與常量類代碼如下:
1 <?xml version="1.0" encoding="utf-8" ?> 2 <configuration> 3 <appSettings> 4 <add key="ClassDefined" value="namespace CSharp.Dynamic{ 5 public class Employee{ 6 public int ID { get; set; } 7 public string Name { get; set; } 8 public string Department { get; set; } 9 public string Position { get; set; } 10 public string Method(string parm){return parm+this.ID.ToString();} 11 }}"/> 12 </appSettings> 13 </configuration> 14 15 16 /* 17 * 18 * 創建人:李林峰 19 * 20 * 時 間:2012-7-23 21 * 22 * 描 述:常量類 23 * 24 */ 25 26 using System.Configuration; 27 28 namespace CSharp.Dynamic 29 { 30 class Constant 31 { 32 /// <summary> 33 /// 程序集名稱 34 /// </summary> 35 public static string CLASSDEFINED = ConfigurationManager.AppSettings["ClassDefined"]; 36 } 37 }
CSharp.Dynamic的主程序類代碼如下:
1 /* 2 * 3 * 創建人:李林峰 4 * 5 * 時 間:2012-7-23 6 * 7 * 描 述:利用反射動創建類實例 8 * 9 */ 10 11 using System; 12 using System.CodeDom.Compiler; 13 using Microsoft.CSharp; 14 using System.Reflection; 15 16 namespace CSharp.Dynamic 17 { 18 class Program 19 { 20 static void Main(string[] args) 21 { 22 //在App.Config中讀取類的定義字符串 23 string ClassDefined = Constant.CLASSDEFINED; 24 //創建代碼編譯器 25 CSharpCodeProvider codeProvider = new CSharpCodeProvider(); 26 //設置編譯參數 27 CompilerParameters paras = new CompilerParameters(); 28 //設置在內存中生成輸出。 29 paras.GenerateInMemory = true; 30 //編譯代碼 31 CompilerResults result = codeProvider.CompileAssemblyFromSource(paras, ClassDefined); 32 //獲取編譯后的程序集 33 Assembly assembly = result.CompiledAssembly; 34 //獲取反射出來的對象 35 Object dynamicClass = assembly.CreateInstance("CSharp.Dynamic.Employee"); 36 //獲取員工實例的類型 37 Type employee = dynamicClass.GetType(); 38 //設置屬性 39 employee.GetProperty("ID").SetValue(dynamicClass, 1, null); 40 employee.GetProperty("Name").SetValue(dynamicClass, "李林峰", null); 41 employee.GetProperty("Department").SetValue(dynamicClass, "技術部", null); 42 employee.GetProperty("Position").SetValue(dynamicClass, "程序員", null); 43 //讀取屬性 44 string Name = employee.GetProperty("Name").GetValue(dynamicClass, null).ToString(); 45 string Department = employee.GetProperty("Department").GetValue(dynamicClass, null).ToString(); 46 string Position = employee.GetProperty("Position").GetValue(dynamicClass, null).ToString(); 47 //執行方法 48 string ParmAndID = employee.GetMethod("Method").Invoke(dynamicClass, new object[] { "員工編號:" }).ToString(); 49 //輸出 50 Console.WriteLine(Name); 51 Console.WriteLine(Department); 52 Console.WriteLine(Position); 53 Console.WriteLine(ParmAndID); 54 } 55 } 56 }
我們在App.config中定義了Employee類的結構,通過string ClassDefined = Constant.CLASSDEFINED;把字符串引用到程序中,並進行一系統的處理。
反射創建類的步驟如下:
- 用字符串定義類的結構。
- 創建代碼編譯器並編譯。
- 獲取編譯后的程序集並反射出類的對象和類型。
- 屬性、方法、事件等......賦值。
- 使用屬性、方法、事件等......。
- 如果編譯參數設置成內存輸入[paras.GenerateInMemory = true;],則由.net 內存回收托管,否則在Temp[C:\Users\Administrator\AppData\Local\Temp]文件夾中產生臨時文件"隨機字符.dll",每運行一次該程序都將會產生一個新的DLL。
在上例中,除了導入了System.Reflection名稱空間外還導入了System.CodeDom.Compiler與Microsoft.CSharp。
System.CodeDom.Compiler:支持編程語言的源代碼的生成和編譯進行管理。具體參考:http://msdn.microsoft.com/zh-cn/library/z6b99ydt
Microsoft.CSharp:編譯和生成代碼,名稱空間下只有一個類CSharpCodeProvider。具體參考:http://msdn.microsoft.com/zh-cn/library/microsoft.csharp.aspx
設置屬性:employee.GetProperty("ID").SetValue(dynamicClass, 1, null);
1 public virtual void SetValue( 2 Object obj, 3 Object value, 4 Object[] index 5 ) 6 7 參數 8 obj 9 類型:System.Object 10 將設置其屬性值的對象。 11 12 value 13 類型:System.Object 14 此屬性的新值。 15 16 index 17 類型:System.Object[] 18 索引化屬性的可選索引值。 對於非索引化屬性,該值應為 null。
讀取屬性:employee.GetProperty("Name").GetValue(dynamicClass, null);
1 public virtual Object GetValue( 2 Object obj, 3 Object[] index 4 ) 5 6 參數 7 obj 8 類型:System.Object 9 將返回其屬性值的對象。 10 11 index 12 類型:System.Object[] 13 索引化屬性的可選索引值。 對於非索引化屬性,該值應為 null。 14 15 返回值 16 類型:System.Object 17 obj 參數指定的對象的屬性值。
執行方法:employee.GetMethod("Method").Invoke(dynamicClass, new object[] { "員工編號:" });
1 public Object Invoke( 2 Object obj, 3 Object[] parameters 4 ) 5 6 參數 7 obj 8 類型:System.Object 9 實體對象。 10 11 Object[] parameters 12 類型:System.Object[] 13 參數數組,如果參數為空,該值應為 null。 14 15 返回值 16 類型:System.Object 17 obj 參數指定的對象的屬性值。
上面的三個方法中的employee為類型,dynamicClass對象的實例。
運行效果如下圖所示:
四、總結
反射在實際應用中還是比較廣泛的,從設計模式的典型"抽象工廠模式"到我們平時應用到的"框架",都會用到反射,其原理大多是動態創建類,如:根據數據庫的字段動態生成類,執行些方法等等。為了在介紹"C#教程之自己動手寫映射"的課程,這里我只對反射常用的方法進行了講解,如果感興趣的話可查看MSND繼續研究。
五、源碼下載
六、版權
轉載請注明出處:http://www.cnblogs.com/iamlilinfeng