Net反射在項目中的應用


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();

 

這樣就可以直接根據接口類找到他對應的實現類,

 

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM