本篇是我學習反射的一個應用小場景而作的學習筆記,主要是一個小的總結,並對各個步驟的記錄,以便未來回顧。框架
這裏假定咱們要開發一個記事本,選擇Windows Form技術開發,界面以下圖所示:函數
該記事本只提供了一個TextBox供輸入,以及保存到指定文件。其餘功能均沒有實現,假定咱們先把這個版本作出來,後續功能經過插件形式一步一步完成。學習
可是,爲了可以使用插件,咱們的主項目還得通過一些改造:測試
(1)加載時須要從插件目錄中獲取插件ui
public FormMain() { InitializeComponent(); // 加載插件 LoadPlugins(); } private void LoadPlugins() { // 1.加載plugins目錄下的全部的dll文件 string plugins = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "plugins"); // 1.1 搜索plugins目錄下的全部的dll文件 string[] dlls = Directory.GetFiles(plugins, "*.dll"); // 2.循環將每一個dll文件都加載起來 foreach (string dllPath in dlls) { // 2.1 動態加載當前循環的dll文件 Assembly assembly = Assembly.LoadFile(dllPath); // 2.2 獲取當前dll中的全部的public類型 Type[] types = assembly.GetExportedTypes(); // 2.3 獲取IEditor接口的Type Type typeIEditor = typeof(IEditor); for (int i = 0; i < types.Length; i++) { // 2.4 驗證當前的類型即實現了IEditor接口而且該類型還能夠被實例化 if (typeIEditor.IsAssignableFrom(types[i]) && !types[i].IsAbstract) { IEditor editor = (IEditor)Activator.CreateInstance(types[i]); // 2.5 向菜單欄中動態添加一個菜單項 ToolStripItem toolItem = toolstripEditMenu.DropDownItems.Add(editor.PluginName); // 2.6 爲剛剛增長的菜單項註冊一個單擊事件 toolItem.Click += new EventHandler(toolItem_Click); toolItem.Tag = editor; } } } }
(2)爲插件設置通用的Click事件this
private void toolItem_Click(object sender, EventArgs e) { ToolStripItem item = sender as ToolStripItem; if (item != null) { if (item.Tag != null) { IEditor editor = item.Tag as IEditor; if (editor != null) { // 運行該插件 editor.Execute(this.txtContent); } } }
這裏約定全部插件都實現了IEditor接口,而且全部插件的功能都在Execute方法中被實現。spa
不難發現,若是咱們直接使用反射調用dll,即便咱們找到了dll文件,也無法知道里面的函數叫什麼名字,即便能夠枚舉出來,也無法智能的調用裏面的函數,實現咱們預期的功能擴展。因而咱們犯難了,咱們已經寫好的程序哪能預料之後會調用哪些dll的哪些函數呢?插件
其實這個並不複雜,咱們能夠利用接口技術實現這樣一種功能。所謂接口,就是一份協議,當你們編寫dll時都遵照這樣一個協議,那麼咱們寫的dll就能夠方便的被exe調用。設計
對於這個小demo而言,咱們設計一個IEditor接口以下:3d
public interface IEditor { string PluginName { get; } void Execute(TextBox txtbox); }
其中,PluginName是插件的名稱,用於菜單顯示。Execute方法則接收記事本的TextBox控件,用於實現具體的功能。
(1)插件1:將文本所有轉爲大寫
新建一個類庫項目,設計一個實現IEditor接口的類:
public class ChangeFontStyle : IEditor { public string PluginName { get { return "轉爲大寫"; } } public void Execute(TextBox txtbox) { if (!string.IsNullOrEmpty(txtbox.Text)) { txtbox.Text = txtbox.Text.ToUpper(); } else { MessageBox.Show("請先輸入文字!"); } }
(2)插件2:將文本所有變爲紅色
新建一個類庫項目,設計一個實現IEditor接口的類:
public class ChangeFontColor : IEditor { public string PluginName { get { return "改變顏色"; } } public void Execute(TextBox txtbox) { if (!string.IsNullOrEmpty(txtbox.Text)) { txtbox.ForeColor = System.Drawing.Color.Red; } else { MessageBox.Show("請先輸入文字!"); } } }
(1)沒有任何插件的記事本程序
Plugins 插件目錄下一個dll也木有:
所以咱們的記事本只有最基本的操做:
(2)加入插件1(轉換大寫)的記事本程序
Plugins 插件目錄有一個dll:
這時加入了轉換大寫的功能:
(3)加入插件2(改變顏色)的記事本程序
Plugins 插件目錄有兩個dll:
這時加入了改變顏色的功能:
由此可知,利用反射和接口,咱們能夠自定義插件實現不一樣的擴展功能,讓咱們的主軟件項目更爲強大!