發(fā)文章
發(fā)文工具
撰寫
網(wǎng)文摘手
文檔
視頻
思維導(dǎo)圖
隨筆
相冊(cè)
原創(chuàng)同步助手
其他工具
圖片轉(zhuǎn)文字
文件清理
AI助手
留言交流
反射的概念和基本原理msdn很詳細(xì),這個(gè)文章主要說(shuō)說(shuō)反射在我的項(xiàng)目中的應(yīng)用
反射用的比較多一個(gè)概念是程序集,也可以認(rèn)為就是dll類庫(kù),程序集是所有類型的集合,它還有一個(gè)重要的東西就是元數(shù)據(jù)。JIT就是利用程序集的TypeRef和AssemblyRef等元數(shù)據(jù)來(lái)確定所引用的程序集及類型,這些元數(shù)據(jù)包括名稱、版本、語(yǔ)言文化和公鑰標(biāo)記等,JIT就是根據(jù)這些信息來(lái)加載一個(gè)程序集到應(yīng)用程序域中。如果要自己加載一個(gè)程序集,可以調(diào)用類型Assembly的LoadXXX系列方法。從Assembly中可以讀到這個(gè)dll中所以類,類的繼承接口,類的方法,屬性,字段,事件等等。
反射和接口
反射是在運(yùn)行中動(dòng)態(tài)的創(chuàng)建需要的類,接口和接口的方法在編譯的時(shí)候已經(jīng)確定了,接口的實(shí)現(xiàn)依賴他的繼承類,有了繼承類,接口才能實(shí)例化使用定義好的方法。
反射就是把接口的實(shí)例化推遲到運(yùn)行階段。所以反射一般和接口搭配使用。
應(yīng)用場(chǎng)景一:?jiǎn)蝹€(gè)接口對(duì)應(yīng)多個(gè)實(shí)現(xiàn)
這個(gè)場(chǎng)景比較多,而且在抽象工廠模式中我覺(jué)得用的很多,典型的例子是數(shù)據(jù)讀取層。一個(gè)項(xiàng)目可能用到SqlSever,Access,Orace或者Txt,XML來(lái)當(dāng)存取數(shù)據(jù),他們的方法都是統(tǒng)一,比如增,刪,修,讀等
這個(gè)時(shí)候就是定義一個(gè)IDataAccess接口,這個(gè)接口定義了統(tǒng)一的方法,增,刪,修,讀等,然后分別用不同的實(shí)現(xiàn)類來(lái)繼承這個(gè)接口,
比如SqlServer類,XmL類,定義為SqlServerDataAccess,XMLDataAccess,他們都繼承IDataAccess
在應(yīng)用的時(shí)候項(xiàng)目可以通過(guò)簡(jiǎn)單的修改或者配置來(lái)使用Sqlserver或者XML數(shù)據(jù)庫(kù),這個(gè)時(shí)候就可以使用反射來(lái)決定接口IDataAccess到底使用哪個(gè)實(shí)現(xiàn)類
抽象工廠模式中使用配置文件來(lái)設(shè)置使用Sqlserver還是XML數(shù)據(jù)實(shí)現(xiàn)類。在配置文件中定義“程序集和命名空間類名”的信息,這樣通過(guò)修改配置文件就可以決定使用
Sqlserver還是XML數(shù)據(jù)實(shí)現(xiàn)類
public IDataAccess CreateDatAccess()
{
IDataAccess IDA =(IDataAccess)Assembly.Load("配置節(jié)點(diǎn)程序集").CreateInstance("命名空間.Sqlserver");
//IDataAccess IDA =(IDataAccess)Assembly.Load("配置節(jié)點(diǎn)程序集").CreateInstance("命名空間.XML");
return IDA;
}
應(yīng)用場(chǎng)景二:多個(gè)接口和多個(gè)實(shí)現(xiàn)類
這個(gè)例子的完全可以使用第一個(gè)場(chǎng)景的方案來(lái)解決,但是由于接口多,實(shí)現(xiàn)類,實(shí)現(xiàn)起來(lái)比較復(fù)雜
這個(gè)例子說(shuō)的是多個(gè)接口,每個(gè)接口可能有一個(gè)實(shí)現(xiàn)類,也可能有多個(gè)實(shí)現(xiàn)類。
基本實(shí)現(xiàn)思路通過(guò)遍歷bin下的文件夾,得到dll信息,把接口和對(duì)應(yīng)的實(shí)現(xiàn)類組織到字典集合中,然后根據(jù)一個(gè)接口信息就可以得到實(shí)現(xiàn)類,實(shí)現(xiàn)接口的動(dòng)態(tài)實(shí)例化
如果接口只有一個(gè)實(shí)現(xiàn)類就直接取得這個(gè)類,如果接口有多個(gè)實(shí)現(xiàn)類那就傳遞一個(gè)類的名稱來(lái)明確要求讀取哪個(gè)類
具體實(shí)現(xiàn),為了更好的項(xiàng)目結(jié)構(gòu),建立一個(gè)接口dll,然后不同的接口對(duì)應(yīng)不同的dll類庫(kù),實(shí)現(xiàn)類的項(xiàng)目名稱最好有個(gè)規(guī)格,方便在遍歷文件夾的時(shí)候讀取特定名稱的dll,加快遍歷速度。
項(xiàng)目結(jié)構(gòu)如圖:
在ConsoleApplication2.Framework定義兩個(gè)接口
public interface ICar { void Run(); } public interface IProduct { void OutputName(); }
在ConsoleApplication2.Impl.Product定義產(chǎn)品接口實(shí)現(xiàn)類
public class ProductA : IProduct { public void OutputName() { Console.WriteLine("Product A Name..."); } }
在ConsoleApplication2.Impl.Car定義ICar實(shí)現(xiàn)類
public class AudiCar : ICar { public void Run() { Console.WriteLine("Audi Car Run..."); } } public class QQCar : ICar { public void Run() { Console.WriteLine("QQ Car Run..."); } }
然后開始重點(diǎn)代碼部分
1.建立接口和實(shí)現(xiàn)類的對(duì)應(yīng)關(guān)系,保存到字典集合中
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"))//遍歷程序下的類似命名規(guī)范的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();//該類繼承的接口,可能是多個(gè)接口 foreach (Type inter in interfaces)//建立接口和實(shí)現(xiàn)類的對(duì)應(yīng)關(guān)系,一個(gè)接口可能多個(gè)實(shí)現(xiàn)類 { if (!dictionary.ContainsKey(inter)) { dictionary.Add(inter, new List<Type>()); } dictionary[inter].Add(type); } } } }
在根據(jù)接口讀取實(shí)現(xiàn)類,因?yàn)榻涌诓煌?,所以用泛型?lái)實(shí)現(xiàn)
//specifiedImplType參數(shù)可以為空,如果一個(gè)接口有多個(gè)實(shí)現(xiàn)類的時(shí)候,需要特別指定使用哪個(gè)實(shí)現(xiàn)類 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 == "")//讀字典集合中根據(jù)接口key得到實(shí)現(xiàn)類Type { implType = dictionary[interfaceType].First(); } else { implType = dictionary[interfaceType].Where(p => p.Name == specifiedImplType).FirstOrDefault(); } return Activator.CreateInstance(implType) as T;//Activator.CreateInstance該語(yǔ)法創(chuàng)建類的實(shí)例,并且As 轉(zhuǎn)換為T類型 } else { throw new Exception("沒(méi)有繼承對(duì)象"); } }
最后測(cè)試運(yùn)行
GetInterfaceAndType();//建立接口和實(shí)現(xiàn)類的對(duì)應(yīng)集合 ICar iCar = GetImpTypeByInterface<ICar>();//默認(rèn)第一個(gè)實(shí)現(xiàn)類 iCar.Run(); ICar iCar = GetImpTypeByInterface<ICar>(“QQCar”);//指定實(shí)現(xiàn)類 iCar.Run();
來(lái)自: 昵稱10504424 > 《工作》
0條評(píng)論
發(fā)表
請(qǐng)遵守用戶 評(píng)論公約
什么是反射、反射可以做些什么
WriteLine(''請(qǐng)輸入對(duì)象類名'');string className = Console.ReadLine();Console.WriteLine(''請(qǐng)輸入要執(zhí)行的...
.Net core 的熱插拔機(jī)制的深入探索,以及卸載問(wèn)題求救指南.
Load和LoadUnmanagedDll函數(shù)實(shí)際上是給開發(fā)者手動(dòng)加載程序集使用的, 自動(dòng)加載應(yīng)放到Resolving和ResolvingUnmanagedDll事件中 原因是,這樣的加載順序不會(huì)導(dǎo)致項(xiàng)目的程序集覆蓋插件的程序集,造成程序集加...
C#反射
WriteLine("This''''''''s t.type={0},w.type={1}, x.type={2},t:{3},w:{4},x:{5}", t...
【C#】反射的用法及效率對(duì)比
C# 反射的基本使用方法
//泛型類+泛型函數(shù)的反射使用 Type typeG = assembly.GetType("dll名稱.類名 `1"); //獲取類型信息 一個(gè)泛...
(9)程序集的加載和反射
GetType 方法返回表示【實(shí)例類型】的 Type 對(duì)象。h) MakeGenericType 方法返回 Type 對(duì)象,該對(duì)象表示構(gòu)造泛型類型,如果該對(duì)象...
DotNet動(dòng)態(tài)創(chuàng)建類
'' 構(gòu)造DLL文件的全路徑 Dim dllName As String = String.Format("{0}\{1}.dll", _ DLLPath, _ sourceFile.Name.Replace(".", "_"))MapPath("~/App_Code/C...
.Net應(yīng)用程序的執(zhí)行環(huán)境(CLR關(guān)于Assembly的搜索算法)
如果GAC里面的NetLibaryTest.dll文件放到GAC中去了,則最后NetVersionTest.exe首先會(huì)從GAC中里面去尋找,即最后輸出:”GAC”如果NetLibar...
C#Assembly詳解
一些情況下,你可以發(fā)現(xiàn)多個(gè)應(yīng)用程序需要使用共享的assembly而不只是使用他們自己的,對(duì)這種情況,你可以在全局assembly緩存(譯者:Global Assembly Cache,這個(gè)翻譯有點(diǎn)不倫不類,大家明白就好)中管理...
微信掃碼,在手機(jī)上查看選中內(nèi)容