開篇先熟悉兩個小概念:
早綁定:是指在編譯時間綁定對象的類型
晚綁定:是指在運行時才綁定對象的類型。
當然我們提到上面兩個概念,肯定是為了引入今天的主題——利用反射實現晚綁定(也就是動態載入類型,並調用它們)。
我暫時只是為了測試的方便先定義一個不能執行的程式集(Person.dll)無需寫的完善,僅僅作為測試使用,之後我們在這個程式中調用它。
person.dll內部如下:
person.dll
1 using System; 2 public class Chinese 3 { 4 private string language; 5 private string name; 6 private int age; 7 private string like; 8 public string Like 9 {10 get { return like; }11 set { like = value; }12 } 13 public string Language14 {15 get { return language; }16 set { language = value; }17 }18 public string Name19 {20 get { return name; }21 set { name = value; }22 }23 public int Age24 {25 get { return age; }26 set { age = value; }27 }28 public virtual void Favourite()29 {30 Console.WriteLine(name+"今年"+age+歲"喜歡的運動是:"+this.like);31 }32 public Chinese()33 { 34 }35 public Chiese(string name, int age)36 {37 this.name = name;38 this.age = age;39 }40 }
注意:當我們不用vs產生注意程式集的時候,一定要注意主程式運行時不能低於該程式集的運行時,預設的使用命令提示執行時使用的是最新的運行時:例如:我這裡執行了:
之後執行主程式報錯,於是更新了一下運行時版本就OK了。
如果我們這樣定義:就會發生早綁定,因為編譯時間,編譯器將從程式集中匯入Chinese類。
Chiesep1=new Chiese("小強",18);
那麼我們怎麼實現晚綁定呢?
現在我們再看下開篇晚綁定的概念,也就是說我們這裡實現的效果是:不會再中繼資料中嵌入對類型的引用,而是在運行是通過反射來實現。現在我們就開始動態載入類型和調用方法。先看一種方式:
- 使用Assembly類的Load方法來動態來動態載入指定的程式集。
- 使用Assembly類的GetType方法來動態載入指定的類型。
- 通過Type類的InvokeMember方法來調用Type對象所表示的類型方法。
下面的代碼示範如歌動態載入程式集Person.dll,動態載入Chinese類型,並調用Favourite方法:
1 using System; 2 using System.IO; 3 using System.Reflection; 4 5 namespace 動態載入類型 6 { 7 class Program 8 { 9 static void Main()10 {11 //載入程式集12 string assemblyPath = Path.Combine(Environment.CurrentDirectory, "person.dll");13 Assembly a = Assembly.LoadFrom(assemblyPath);14 //擷取指定的類型15 Type t = a.GetType("Chinese");16 //構造類型執行個體17 Object[] args = new Object[] { "小強",18 };18 Object obj = t.InvokeMember(null,19 BindingFlags.DeclaredOnly | //指定綁定類型20 BindingFlags.Public | BindingFlags.NonPublic |21 BindingFlags.Instance | BindingFlags.CreateInstance, null, null, args);22 Console.WriteLine("新建立的類型: " + obj.GetType().ToString());23 Console.WriteLine("================");24 //給欄位like賦值25 t.InvokeMember("like",26 BindingFlags.DeclaredOnly |27 BindingFlags.Public | BindingFlags.NonPublic |28 BindingFlags.Instance | BindingFlags.SetField, null, obj, new Object[] { "抓籃球" });29 //調用方法30 t.InvokeMember("Favourite", BindingFlags.DeclaredOnly |31 BindingFlags.Public | BindingFlags.NonPublic |32 BindingFlags.Instance | BindingFlags.InvokeMethod, null, obj, null);33 Console.ReadKey();34 }35 }36 }
利用System.Activator類
承接上面的執行個體更簡單的載入類型的方法,就是利用System.Activator類。
該類包含特定的方法,用以在本地或從遠程建立物件類型,或擷取對現有遠程對象的引用。此類不能被繼承。
步驟如下:
1.載入程式集並調用GetType方法擷取目標類型對象
2.調用Activator.CreateInstance(Type)使用指定類型的預設建構函式來建立該類型的執行個體,並通過Type對象的GetMethod方法來擷取MethodInfo對象
3.使用MethodInfo對象的Invoke方法來動態執行方法。
1 using System; 2 using System.Reflection; 3 4 namespace Test 5 { 6 class Program 7 { 8 static void Main() 9 {10 Assembly a = Assembly.Load("person.dll");11 Type t = a.GetType("Chinese");12 Object[] args = new Object[] { "小強", 18 };13 object obj = Activator.CreateInstance(t, args);14 MethodInfo mi = t.GetMethod("Favourite");15 mi.Invoke(obj, null);16 Console.ReadKey();17 }18 }19 }
執行: