1 反射技術與設計模式
反射(Reflection)是。NET中的重要機制,通過放射,可以在運行時獲得。NET中每一個類型(包括類、結構、委托、接口和枚舉等)的成員,包括方法、屬性、事件,以及構造函數等。還可以獲得每個成員的名稱、限定符和參數等。有了反射,即可對每一個類型了如指掌。如果獲得了構造函數的信息,即可直接創建對象,即使這個對象的類型在編譯時還不知道。
1.1 .NET可執行應用程序結構
程序代碼在編譯後生成可執行的應用,我們首先要了解這種可執行應用程序的結構。
應用程序結構分為應用程序域—程序集—模塊—類型—成員幾個層次,公共語言運行庫加載器管理應用程序域,這種管理包括將每個程序集加載到相應的應用程序域以及控制每個程序集中類型層次結構的內存布局。
程序集包含模塊,而模塊包含類型,類型又包含成員,反射則提供了封裝程序集、模塊和類型的對象。我們可以使用反射動態地創建類型的實例,將類型綁定到現有對象或從現有對象中獲取類型,然後調用類型的方法或訪問其字段和屬性。反射通常具有以下用途。
(1)使用Assembly定義和加載程序集,加載在程序集清單中列出模塊,以及從此程序集中查找類型並創建該類型的實例。
(2)使用Module了解包含模塊的程序集以及模塊中的類等,還可以獲取在模塊上定義的所有全局方法或其他特定的非全局方法。
(3)使用ConstructorInfo了解構造函數的名稱、參數、訪問修飾符(如pulic 或private)和實現詳細信息(如abstract或virtual)等。使用Type的GetConstructors或GetConstructor方法來調用特定的構造函數。
(4)使用MethodInfo了解方法的名稱、返回類型、參數、訪問修飾符(如pulic 或private)和實現詳細信息(如abstract或virtual)等。使用Type的GetMethods或GetMethod方法來調用特定的方法。
(5)使用FiedInfo了解字段的名稱、訪問修飾符(如public或private)和實現詳細信息(如static)等,並獲取或設置字段值。
(6)使用EventInfo了解事件的名稱、事件處理程序數據類型、自定義屬性、聲明類型和反射類型等,添加或移除事件處理程序。
(7)使用PropertyInfo了解屬性的名稱、數據類型、聲明類型、反射類型和只讀或可寫狀態等,獲取或設置屬性值。
(8)使用ParameterInfo了解參數的名稱、數據類型、是輸入參數還是輸出參數,以及參數在方法簽名中的位置等。
System.Reflection.Emit命名空間的類提供了一種特殊形式的反射,可以在運行時構造類型。
反射也可用於創建稱為類型浏覽器的應用程序,使用戶能夠選擇類型,然後查看有關選定類型的信息。
此外,Jscript等語言編譯器使用反射來構造符號表。System.Runtime.Serialization命名空間中的類使用反射來訪問數據並確定要永久保存的字段,System.Runtime.Remoting命名空間中的類通過序列化來間接地使用反射。
(5)使用FiedInfo了解字段的名稱、訪問修飾符(如public或private)和實現詳細信息(如static)等,並獲取或設置字段值。System.Runtime.Serialization命名空間中的類使用反射來訪問數據並確定要永久保存的字段,System.Runtime.Remoting命名空間中的類通過序列化來間接地使用反射。
1.2 反射技術示例
下面是反射技術的示例,我們可以在程序去得時動態實例化對象,獲得對象的屬性,並調用對象的方法。
1Namespace ReflectionExample
2{
3 class Class1
4 {
5 [STAThread]
6 static void Main (string [ ] args)
7 {
8 System.Console.WriteLine(“列出程序集中的所有類型”);
9 Assembly a = Assembly.LoadFrom (“ReflectionExample.exe”);
10 Type[ ] mytypes = a.GetTypes( );
11
12 Foreach (Type t in mytypes)
13 {
14 System.Console.WriteLine ( t.Name );
15 }
16 System.Console.ReadLine ( );
17 System.Console.WriteLine (“列出HellWord中的所有方法” );
18 Type ht = typeof(HelloWorld);
19 MethodInfo[] mif = ht.GetMethods();
20 foreach(MethodInfo mf in mif)
21 {
22 System.Console.WriteLine(mf.Name);
23 }
24 System.Console.ReadLine();
25 System.Console.WriteLine("實例化HelloWorld,並調用SayHello方法");
26 Object obj = Activator.CreateInstance(ht);
27 string[] s = {"zhenlei"};
28 Object bojName = Activator.CreateInstance(ht,s);
29 BindingFlags flags = (BindingFlags.NonPublic|BindingFlags. Public|BindingFlags.Static|BindingFlags.Instance|BindingFlags. DeclaredOnly);
30 MethodInfo msayhello = ht.GetMethod("SayHello");
31 msayhello.Invoke(obj,null);
32 msayhello.Invoke(objName,null);
33 System.Console.ReadLine();
34 }
35 }
36}
1using System;
2namespace ReflectionExample
3{
4 public class HelloWorld
5 {
6 string myName = null;
7 public HelloWorld(string name)
8 {
9 myName = name;
10 }
11 public HelloWorld() : this(null)
12 {}
13 public string Name
14 {
15 get
16 {
17 return myName;
18 }
19 }
20 public void SayHello()
21 {
22 if(myName == null)
23 {
24 System.Console.WriteLine("Hello World");
25 }
26 else
27 {
28 System.Console.WriteLine("Hello," + myName);
29 }
30 }
31 }
32}
33
1.3 在設計模式實現中使用反射技術采用反射技術可以簡化工廠的實現。
(1)工廠方法:通過反射可以將需要實現的子類名稱傳遞給工廠方法,這樣無須在子類中實現類的實例化。
(2)抽象工廠:使用反射可以減少抽象工廠的子類。
采用反射技術可以簡化工廠代碼的復雜程度,在。NET項目中,采用反射技術的工廠已經基本代替了工廠方法。
采用反射技術可以極大地簡化對象的生成,對以下設計模式的實現也有很大影響。
(1)命令模式:可以采用命令的類型名稱作為參數直接獲得命令的實例,並且可以動態執行命令。
(2)享元模式:采用反射技術實例化享元可以簡化享元工廠。