C#教程之自己動手寫映射第三節[反射]


朋友炒股兩個月賺了10萬,我幫他推廣一下公眾號,把錢用來投資總比放銀行連通貨膨脹都跑不過里強硬核離職,在家炒股 ,這是他每天的日志,有些經驗是花錢也買不到的。

一、什么是反射

  MSND:反射提供了封裝程序集、模塊和類型的對象(Type 類型)。可以使用反射動態創建類型的實例,將類型綁定到現有對象,或從現有對象獲取類型並調用其方法或訪問其字段和屬性。如果代碼中使用了屬性,可以利用反射對它們進行訪問。

  實用概念:反射是在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為反射。

  反射的名稱空間:System.Reflection,具體參考 http://msdn.microsoft.com/zh-cn/library/system.reflection.aspx

二、利用反射動態創建類的實例

  前置條件:我們創建兩個項目來展示反射的簡單應用

  1. CSharp.Model:類庫,Employee.cs,我們要反射的測試實體類
  2. 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文件來描述類。

  前置條件:

  1. 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;把字符串引用到程序中,並進行一系統的處理。

  反射創建類的步驟如下:

  1. 用字符串定義類的結構。
  2. 創建代碼編譯器並編譯。
  3. 獲取編譯后的程序集並反射出類的對象和類型。
  4. 屬性、方法、事件等......賦值。
  5. 使用屬性、方法、事件等......。
  6. 如果編譯參數設置成內存輸入[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 索引化屬性的可選索引值。 對於非索引化屬性,該值應為 null14 
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  參數數組,如果參數為空,該值應為 null14  
15  返回值
16  類型:System.Object
17  obj 參數指定的對象的屬性值。

  上面的三個方法中的employee為類型,dynamicClass對象的實例。

  運行效果如下圖所示:

 

 

四、總結

   反射在實際應用中還是比較廣泛的,從設計模式的典型"抽象工廠模式"到我們平時應用到的"框架",都會用到反射,其原理大多是動態創建類,如:根據數據庫的字段動態生成類,執行些方法等等。為了在介紹"C#教程之自己動手寫映射"的課程,這里我只對反射常用的方法進行了講解,如果感興趣的話可查看MSND繼續研究。

五、源碼下載

  06CSharp映射教程_03.rar

六、版權

  轉載請注明出處:http://www.cnblogs.com/iamlilinfeng

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM