反射的概念和基本原理msdn很詳細這個文章主要說說反射在我的項目中的應用
反射用的比較多一個概念是程序集也可以認為就是dll類庫程序集是所有類型的集合它還有一個重要的東西就是元數據JIT就是利用程序集的TypeRef和AssemblyRef等元數據來確定所引用的程序集及類型這些元數據包括名稱版本語言文化和公鑰標記等JIT就是根據這些信息來加載一個程序集到應用程序域中如果要自己加載一個程序集可以調用類型Assembly的LoadXXX系列方法從Assembly中可以讀到這個dll中所以類類的繼承接口類的方法屬性字段事件等等
反射和接口
反射是在運行中動態的創建需要的類接口和接口的方法在編譯的時候已經確定了接口的實現依賴他的繼承類有了繼承類接口才能實例化使用定義好的方法
反射就是把接口的實例化推遲到運行階段所以反射一般和接口搭配使用
應用場景一單個接口對應多個實現
這個場景比較多而且在抽象工廠模式中我覺得用的很多典型的例子是數據讀取層
一個項目可能用到SqlSeverAccessOrace或者TxtXML來當存取數據他們的方法都是統一比如增刪修讀等
這個時候就是定義一個IDataAccess接口這個接口定義了統一的方法增刪修讀等然後分別用不同的實現類來繼承這個接口
比如SqlServer類XmL類定義為SqlServerDataAccessXMLDataAccess他們都繼承IDataAccess
在應用的時候項目可以通過簡單的修改或者配置來使用Sqlserver或者XML數據庫這個時候就可以使用反射來決定接口IDataAccess到底使用哪個實現類
抽象工廠模式中使用配置文件來設置使用Sqlserver還是XML數據實現類在配置文件中定義程序集和命名空間類名的信息這樣通過修改配置文件就可以決定使用
Sqlserver還是XML數據實現類
public IDataAccess CreateDatAccess()
{
IDataAccess IDA =(IDataAccess)AssemblyLoad(配置節點程序集)CreateInstance(命名空間Sqlserver);
//IDataAccess IDA =(IDataAccess)AssemblyLoad(配置節點程序集)CreateInstance(命名空間XML);
return IDA;
}
應用場景二多個接口和多個實現類
這個例子的完全可以使用第一個場景的方案來解決但是由於接口多實現類實現起來比較復雜
這個例子說的是多個接口每個接口可能有一個實現類也可能有多個實現類
基本實現思路通過遍歷bin下的文件夾得到dll信息把接口和對應的實現類組織到字典集合中然後根據一個接口信息就可以得到實現類實現接口的動態實例化
如果接口只有一個實現類就直接取得這個類如果接口有多個實現類那就傳遞一個類的名稱來明確要求讀取哪個類
具體實現為了更好的項目結構建立一個接口dll然後不同的接口對應不同的dll類庫實現類的項目名稱最好有個規格方便在遍歷文件夾的時候讀取特定名稱的dll加快遍歷速度
項目結構如圖
在ConsoleApplicationFramework定義兩個接口
public interface ICar { void Run(); } public interface IProduct { void OutputName(); }
在ConsoleApplicationImplProduct定義產品接口實現類
public class ProductA : IProduct { public void OutputName() { ConsoleWriteLine(Product A Name); } }
在ConsoleApplicationImplCar定義ICar實現類
public class AudiCar : ICar { public void Run() { ConsoleWriteLine(Audi Car Run); } } public class QQCar : ICar { public void Run() { ConsoleWriteLine(QQ Car Run); } }
然後開始重點代碼部分
建立接口和實現類的對應關系保存到字典集合中
static Dictionary> dictionary = new Dictionary>();public static void GetInterfaceAndType() { string s = PathGetDirectoryName(AssemblyGetExecutingAssembly()Location); foreach (var file in DirectoryGetFiles(s ConsoleApplicationImpl*dll))//遍歷程序下的類似命名規范的dll { var ass = AssemblyLoad(FileReadAllBytes(file));//得到程序集dll ConsoleWriteLine(assFullName); foreach (Type type in assGetTypes()Where(p=>pIsClass))//遍歷程序集中類 { ConsoleWriteLine(typeFullName); Type[] interfaces = typeGetInterfaces();//該類繼承的接口可能是多個接口 foreach (Type inter in interfaces)//建立接口和實現類的對應關系一個接口可能多個實現類 { if (!dictionaryContainsKey(inter)) { dictionaryAdd(inter new List()); } dictionary[inter]Add(type); } } } }
在根據接口讀取實現類因為接口不同所以用泛型來實現
//specifiedImplType參數可以為空如果一個接口有多個實現類的時候需要特別指定使用哪個實現類 public static T GetImpTypeByInterface(string specifiedImplType = ) where T : class { Type interfaceType = typeof(T);//接口 if (dictionaryCount > && dictionaryContainsKey(interfaceType)) { Type implType = null; if (specifiedImplType == )//讀字典集合中根據接口key得到實現類Type { implType = dictionary[interfaceType]First(); } else { implType = dictionary[interfaceType]Where(p => pName == specifiedImplType)FirstOrDefault(); } return ActivatorCreateInstance(implType) as T;//ActivatorCreateInstance該語法創建類的實例並且As 轉換為T類型 } else { throw new Exception(沒有繼承對象); } }
最後測試運行
GetInterfaceAndType();//建立接口和實現類的對應集合 ICar iCar = GetImpTypeByInterface();//默認第一個實現類 iCarRun(); ICar iCar = GetImpTypeByInterface(QQCar);//指定實現類 iCarRun();
這樣就可以直接根據接口類找到他對應的實現類
From:http://tw.wingwit.com/Article/program/net/201311/11711.html