程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> c# 高級技術--反射

c# 高級技術--反射

編輯:C#入門知識

反射? 難道是物理中光的反射??  NO、NO、NO !!! 這個“反射”和物理一點關系都沒有!!
那什麼是反射呢? 我個人的理解是:在程序中 動態的添加程序的功能(添加dll文件) 無需在源代碼中添加 從而實現為程序的功能“升級”。
說的有些官方了 下面我舉幾個例子
 我們都玩過游戲 就拿我以前玩的QQ飛車來說 游戲廠商會隔一段時間對游戲進行升級 比如說音樂、賽道等 由於QQ飛車的客戶端已經下載到我們
的電腦上了 每次游戲升級的時候不可能讓我們重新下載一遍客戶端吧 要是這樣的話 QQ飛車會被罵死的 那該怎麼辦呢?
 在游戲升級完畢的時候 有沒有注意到 在游戲的安裝目錄下 多了幾個文件夾 文件夾中又多了幾個.dll問文件
哈哈 以前沒有注意到的可以現在去看一下 沒錯 這就是傳說中的“反射”!!
 暈!! 就多了幾個文件 QQ飛車中就能有那麼多音樂 和 那麼多復雜的賽道?
 沒錯 下面我來大概說一下反射的原理吧 我個人的理解 比較膚淺 :
 在我們寫主程序的時候 就比如說QQ飛車的主程序 裡面的功能並不是寫死的 而是留有一個類似於對外接口的東西
這樣做的目的就是為了以後能為主程序添加更多的功能
 在主程序中 分為以下幾個步驟:
  1. 窗體在加載的時候 搜索dll目錄下的所有的.dll文件
     2. 獲取.dll文件中具有插件功能的類
     3. 通過調用插件中類的方法 來實現程序中的功能擴展
     4. 開發主程序的人必去做一個約定:所有為程序開發插件的人 必須將插件執行的方法命名為固定的一個名字
     5. 主程序的開發人員不管開發者插件的人定義了多少個類 多少個方法 在主程序中 只去調用規定好的那個名字的方法 這就是主程序與插件開發者之間的一個約定
主程序代碼:   
 // 窗體在加載的時候
        private void Form1_Load(object sender, EventArgs e)
        {
            // 1. 窗體在加載的時候搜索dll目錄下的所有的.dll文件
            // 1.1 獲取當前運行的exe的絕對路徑
            //Assembly.GetExecutingAssembly().Location;
            // 1.2 獲取當前運行的exe文件路徑的目錄部分
            string exeDirPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
            // 1.3 拼接dll文件的絕對路徑
            string dllFullPath = Path.Combine(exeDirPath, "dll");
            // 1.4 搜索指定目錄下的所有dll文件
            string[] dellPaths = Directory.GetFiles(dllFullPath, "*.dll");
            // 1.5 循環遍歷加載所有的dll文件
            for (int i = 0; i < dellPaths.Length; i++)
            {
                // 將每一個dll都加載進來
                Assembly asm = Assembly.LoadFile(dellPaths[i]);
 
                // 獲取當前dll(插件)中的public類
                Type[] typePublic = asm.GetExportedTypes();
 
                // 獲取接口的類型
                Type typeIExecute = typeof(IExecute);
 
                // 循環判斷 typePublic 中的每個類是否實現了 IExecute 接口
                // 循環判斷改類型是否可以被實例化不是抽象的
                for (int j = 0; j < typePublic.Length; j++)
                {
                    if (typeIExecute.IsAssignableFrom(typePublic[j]) && !typePublic[j].IsAbstract)
                    {
                        // 根據類型的type 創建對象
                        // 由於已經知道 typePublic[j] 是實現了 IExecute 接口的
                        // 所以強轉成IExecute接口然後通過接口變量來操作類的成員了
                        IExecute execut = (IExecute)Activator.CreateInstance(typePublic[j]);
 
                        // 給主程序中的菜單欄名稱賦值
                        ToolStripItem tsoitem = MymenuStrip.Items.Add(execut.ExeName);
 
                        // 給增加的功能實現單擊事件
                        tsoitem.Click += new EventHandler(tsoitem_Click);
 
                        // 將接口對象 execut 放在新增的對象的tag屬性中
                        tsoitem.Tag = execut;
                    }
                }
            }
        }
 
        ///<summary>
        ///給增加的功能實現單擊事件
        ///</summary>
        ///<param name="sender"></param>
        ///<param name="e"></param>
        void tsoitem_Click(object sender, EventArgs e)
        {
            // 轉換成接口的類型
            IExecute execut = (IExecute)((ToolStripItem)sender).Tag;
 
            execut.Execute(textBox1);
        }
 
定義的接口:
public interface IExecute
    {
        ///<summary>
        ///插件的名稱用來顯示在主程序中
        ///</summary>
 
        string ExeName
        {
            get;
            set;
        }
 
        ///<summary>
        ///插件執行的方法
        ///</summary>
        void Execute(TextBox text);
    }
 
  其實我們程序員每天都在應用反射
  我們在使用.的時候 就是應用了反射 當我們.的時候 會反射當前程序的元數據 將所有的方法,類等信息全部顯示出來 方便程序員使用 大大提高了編程效率!
 
 
 

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved