■
dynamic類型
C#從1.0版開始,就可以即使不知道一個對象的類型,在編譯時間也可以動態訪問這個對象的資訊。只要使用反射就可以了。
使用反射訪問對象的成員資訊
class A { public readonly string MyName = "陸淩牛"; public static object GetObjectA() { return new A(); } } class Program { static void Main(string[] args) { object a = A.GetObjectA(); var name = a.GetType().GetField("MyName").GetValue(a); Console.WriteLine(name); } } |
上例的執行結果
誠如您所見,Main方法中並不知道在GetObjectA方法中返回了什麼類型的對象,利用反射功能,可以得到返回對象的欄位的值。也就是說,這就是所謂的“動態”處理。
在C#4.0中匯入了dynamic類型,可以大幅度簡化這種操作。
使用dynamic類型訪問對象的成員資訊
using System; class A { public readonly string MyName = "陸淩牛"; public static dynamic GetObjectA() { return new A(); } } class Program { static void Main(string[] args) { dynamic a = A.GetObjectA(); Console.WriteLine(a.MyName); } } |
當然,在Main中仍然不知道GetObjectA方法返回的對象為A類型,但仍然可以得到MyName這個欄位的值。這是因為,只要名字保持一致,就可以進行訪問了,與反射中的訪問功能是相同的。
也就是說,因為名字是否一致不是在編譯時間檢查的,而是在運行時檢查的。即使不一致,也不是編譯時間錯誤,而是運行時拋出異常。同時,運行時因為要尋找與給定名字相同的成員,運行速度會有相應的延遲。
■ 統一調用
dynamic類型的特徵之一為,雖然不知道對象的類型也可以對對象進行訪問,但在某種情況下即使知道了對象的類型,也必須通過dynamic類型進行訪問。
下例為兩種“鳥”類的定義,這兩個類沒有繼承關係,完全是獨立存在的。這種情況下,用普通的方法不能統一調用它們中的某個方法。即使可以另外進行封裝,但始終還是要分別針對不同的類分開調用。因為象這樣兩個沒有繼承關係的類,要統一調用它們中某個函數是不可能的。但是,現在通過dynamic類型,只要名字,參數與類型保持一致,就可以統一調用了。下例中在統一鳴叫方法中,集中調用了兩個類中的同一個方法。
通過dynamic類型進行訪問
using System; class 黑鳥 { public void 鳴叫() { Console.WriteLine("我是黑鳥!"); } } class 白鳥 { public void 鳴叫() { Console.WriteLine("我是白鳥"); } } class Program { private static void 統一鳴叫(dynamic 鳥) { 鳥.鳴叫(); } static void Main(string[] args) { 統一鳴叫((dynamic)new 黑鳥()); 統一鳴叫((dynamic)new 白鳥()); } } |
上例的執行結果