Net反射在項目中的應用
反射的概念和基本原理msdn很詳細,這個文章主要說說反射在我的項目中的應用
反射用的比較多一個概念是程序集,也可以認為就是dll類庫,程序集是所有類型的集合,它還有一個重要的東西就是元數據。JIT就是利用程序集的TypeRef和AssemblyRef等元數據來確定所引用的程序集及類型,這些元數據包括名稱、版本、語言文化和公鑰標記等,JIT就是根據這些信息來載入一個程序集到應用程序域中。如果要自己載入一個程序集,可以調用類型Assembly的LoadXXX系列方法。從Assembly中可以讀到這個dll中所以類,類的繼承介面,類的方法,屬性,欄位,事件等等。
反射和介面
反射是在運行中動態的創建需要的類,介面和介面的方法在編譯的時候已經確定了,介面的實現依賴他的繼承類,有了繼承類,介面才能實例化使用定義好的方法。
反射就是把介面的實例化推遲到運行階段。所以反射一般和介面搭配使用。
應用場景一:單個介面對應多個實現
這個場景比較多,而且在抽象工廠模式中我覺得用的很多,典型的例子是數據讀取層。一個項目可能用到SqlSever,Access,Orace或者Txt,XML來當存取數據,他們的方法都是統一,比如增,刪,修,讀等
這個時候就是定義一個IDataAccess介面,這個介面定義了統一的方法,增,刪,修,讀等,然後分別用不同的實現類來繼承這個介面,
比如SqlServer類,XmL類,定義為SqlServerDataAccess,XMLDataAccess,他們都繼承IDataAccess
在應用的時候項目可以通過簡單的修改或者配置來使用Sqlserver或者XML資料庫,這個時候就可以使用反射來決定介面IDataAccess到底使用哪個實現類
抽象工廠模式中使用配置文件來設置使用Sqlserver還是XML數據實現類。在配置文件中定義「程序集和命名空間類名」的信息,這樣通過修改配置文件就可以決定使用
Sqlserver還是XML數據實現類
public IDataAccess CreateDatAccess()
{
IDataAccess IDA =(IDataAccess)Assembly.Load("配置節點程序集").CreateInstance("命名空間.Sqlserver");
//IDataAccess IDA =(IDataAccess)Assembly.Load("配置節點程序集").CreateInstance("命名空間.XML");
return IDA;
}
應用場景二:多個介面和多個實現類
這個例子的完全可以使用第一個場景的方案來解決,但是由於介面多,實現類,實現起來比較複雜
這個例子說的是多個介面,每個介面可能有一個實現類,也可能有多個實現類。
基本實現思路通過遍歷bin下的文件夾,得到dll信息,把介面和對應的實現類組織到字典集合中,然後根據一個介面信息就可以得到實現類,實現介面的動態實例化
如果介面只有一個實現類就直接取得這個類,如果介面有多個實現類那就傳遞一個類的名稱來明確要求讀取哪個類
具體實現,為了更好的項目結構,建立一個介面dll,然後不同的介面對應不同的dll類庫,實現類的項目名稱最好有個規格,方便在遍歷文件夾的時候讀取特定名稱的dll,加快遍歷速度。
項目結構如圖:
在ConsoleApplication2.Framework定義兩個介面
public interface ICar { void Run(); } public interface IProduct { void OutputName(); }
在ConsoleApplication2.Impl.Product定義產品介面實現類
public class ProductA : IProduct { public void OutputName() { Console.WriteLine("Product A Name..."); } }
在ConsoleApplication2.Impl.Car定義ICar實現類
public class AudiCar : ICar { public void Run() { Console.WriteLine("Audi Car Run..."); } } public class QQCar : ICar { public void Run() { Console.WriteLine("QQ Car Run..."); } }
然後開始重點代碼部分
1.建立介面和實現類的對應關係,保存到字典集合中
static Dictionary<Type, List<Type>> dictionary = new Dictionary<Type, List<Type>>();public static void GetInterfaceAndType() { string s = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); foreach (var file in Directory.GetFiles(s, "ConsoleApplication2.Impl.*.dll"))//遍歷程序下的類似命名規範的dll, { var ass = Assembly.Load(File.ReadAllBytes(file));//得到程序集dll Console.WriteLine(ass.FullName); foreach (Type type in ass.GetTypes().Where(p=>p.IsClass))//遍歷程序集中類 { Console.WriteLine(type.FullName); Type[] interfaces = type.GetInterfaces();//該類繼承的介面,可能是多個介面 foreach (Type inter in interfaces)//建立介面和實現類的對應關係,一個介面可能多個實現類 { if (!dictionary.ContainsKey(inter)) { dictionary.Add(inter, new List<Type>()); } dictionary[inter].Add(type); } } } }
在根據介面讀取實現類,因為介面不同,所以用泛型來實現
//specifiedImplType參數可以為空,如果一個介面有多個實現類的時候,需要特別指定使用哪個實現類 public static T GetImpTypeByInterface<T>(string specifiedImplType = "") where T : class { Type interfaceType = typeof(T);//介面 if (dictionary.Count > 0 && dictionary.ContainsKey(interfaceType)) { Type implType = null; if (specifiedImplType == "")//讀字典集合中根據介面key得到實現類Type { implType = dictionary[interfaceType].First(); } else { implType = dictionary[interfaceType].Where(p => p.Name == specifiedImplType).FirstOrDefault(); } return Activator.CreateInstance(implType) as T;//Activator.CreateInstance該語法創建類的實例,並且As 轉換為T類型 } else { throw new Exception("沒有繼承對象"); } }
最後測試運行
GetInterfaceAndType();//建立介面和實現類的對應集合 ICar iCar = GetImpTypeByInterface<ICar>();//默認第一個實現類 iCar.Run(); ICar iCar = GetImpTypeByInterface<ICar>(「QQCar」);//指定實現類 iCar.Run();
推薦閱讀:
※《天津市2017年重點文化項目》
※中資項目相繼成形 公寓塔樓閃耀悉尼天際線
※經營項目全部直接免徵增值稅也應正確核算進、銷項稅額
※中國獎牌榜按項目查
※及時雨:分答APP賺錢小項目分享