當然,這里指的是托管的dll與托管的方法,實際上用到的東西大部分是在反射(reflecting)命名空間里頭的。
用途或許廣泛吧,我不是很確信,但這個是在運行期綁定的,那么就不會有編譯期綁定那么僵硬……但也沒有編譯期綁定那么簡單。
可以用於做插件之類的。
先是一個接口,實現了這個接口的類被認為是合法的,可以被載入的……
namespace gp { public delegate void DoWhat(); public interface IInterface { string GetName(); DoWhat dowhat { get; set; } } }
很簡單的接口,一個是用於判斷做什么的函數,另外一個,則是一個方法的委托,做什么。
然后,我們新建一個項目,弄個類實現這個接口:
namespace gp { public delegate void DoWhat(); public interface IInterface { string GetName(); DoWhat dowhat { get; set; } } }
在構造函數里頭將委托加了一個項,當執行那個委托的時候就會執行這個函數。
現在是重要的一個部分,代碼難度不大~~
新建一個windows application,然后在窗體上頭拖一個panel,這個是為了動態加載后將操作按鈕放上去的。。不過可能會重疊,建議考慮用flowlayoutpanel,這個會自動重排以滿足個數,anyway,無所謂,反正是為了闡述概念。
private void Form1_Load(object sender, EventArgs e) { var plugindir = System.IO.Directory.GetParent(System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName).CreateSubdirectory("startup"); foreach (var filesInPlugin in plugindir.GetFiles()) { if (filesInPlugin.Extension.ToLower() == ".dll") { Assembly dllFromPlugin = Assembly.LoadFile(filesInPlugin.FullName); foreach (var dllModule in dllFromPlugin.GetLoadedModules()) { foreach (var typeDefinedInModule in dllModule.GetTypes()) { if (typeDefinedInModule.GetInterfaces().Contains(typeof(gp.IInterface))) { if (typeDefinedInModule.IsClass) { var itemGet = System.Activator.CreateInstance(typeDefinedInModule) as gp.IInterface; LinkLabel ll_now = new LinkLabel(); ll_now.Text = itemGet.GetName(); ll_now.Click += (a, b) => { if (itemGet.dowhat != null)itemGet.dowhat(); }; panel1.Controls.Add(ll_now); } } } } } } }
一個不難看懂的代碼,先是指定插件文件夾的位置,要是沒有就創建一個。然后遍歷里頭為dll類型的文件,再試圖轉載這個文件——實際情況下,這里需要加 try...catch,因為誰也不知道你加載的dll文件倒是是不是合法的dll文件,然后遍歷里頭的模塊,再遍歷模塊里頭的定義的類型——可能是類、 interface、枚舉等等等等,很多很多,取得這個玩意兒的集成的interface,再判斷是不是包含我們的interface。(也就是說,包含了這個interface就算是合法的插件類)
如果包含了的話,判斷這是不是一個類,因為接口也可以在其他的東西里頭被繼承,比如另一個接口等等,而其他這些情況對我們來說毫無意義。
然后,我們動態創建這個類的實例—— System.Activator.CreateInstance,並且進行轉換,轉換為繼承的接口,現在開始就是強類型操作了。我這里做的操作是生成一個linklabel,並且設置名稱和按下執行的方法。。。大概就是這樣,以上。