反射? 難道是物理中光的反射?? 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);
}
其實我們程序員每天都在應用反射
我們在使用.的時候 就是應用了反射 當我們.的時候 會反射當前程序的元數據 將所有的方法,類等信息全部顯示出來 方便程序員使用 大大提高了編程效率!