在.NET中使用反射實現簡易插件機制

  本篇是我學習反射的一個應用小場景而作的學習筆記,主要是一個小的總結,並對各個步驟的記錄,以便未來回顧。框架

1、基礎框架-敏捷基礎版本

  這裏假定咱們要開發一個記事本,選擇Windows Form技術開發,界面以下圖所示:函數

Main

  該記事本只提供了一個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

2、約定接口-可擴展的基礎

plugin

  不難發現,若是咱們直接使用反射調用dll,即便咱們找到了dll文件,也無法知道里面的函數叫什麼名字,即便能夠枚舉出來,也無法智能的調用裏面的函數,實現咱們預期的功能擴展。因而咱們犯難了,咱們已經寫好的程序哪能預料之後會調用哪些dll的哪些函數呢?插件

  其實這個並不複雜,咱們能夠利用接口技術實現這樣一種功能。所謂接口,就是一份協議,當你們編寫dll時都遵照這樣一個協議,那麼咱們寫的dll就能夠方便的被exe調用。設計

  對於這個小demo而言,咱們設計一個IEditor接口以下:3d

    public interface IEditor
    {
        string PluginName
        {
            get;
        }

        void Execute(TextBox txtbox);
    }

  其中,PluginName是插件的名稱,用於菜單顯示。Execute方法則接收記事本的TextBox控件,用於實現具體的功能。

3、實現插件-可升級的功能

  (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("請先輸入文字!");
            }
        }
    }

4、擁抱變化-簡單的測試

  (1)沒有任何插件的記事本程序

    Plugins 插件目錄下一個dll也木有:

NoPlugins

    所以咱們的記事本只有最基本的操做: 

demo1

  (2)加入插件1(轉換大寫)的記事本程序

    Plugins 插件目錄有一個dll:

oneplugin

    這時加入了轉換大寫的功能:

demo2

  (3)加入插件2(改變顏色)的記事本程序

     Plugins 插件目錄有兩個dll:

twopluings

     這時加入了改變顏色的功能:

demo3

  由此可知,利用反射和接口,咱們能夠自定義插件實現不一樣的擴展功能,讓咱們的主軟件項目更爲強大!

 

相關文章
相關標籤/搜索