程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .NET依賴注入原理與實現

.NET依賴注入原理與實現

編輯:關於.NET
不用Unity庫,自己實現.NET輕量級依賴注入


在面向對象的設計中,依賴注入(IoC)作為一種重要的設計模式,主要用於削減計算機程序的耦合問題,相對於Java中的Spring框架來說,微軟企業庫中的Unity框架是目前.NET平台中運用比較廣泛的依賴注入框架之一(還有的Spring.NET等)。但是對於這些“官方版本”的強大依賴注入框架,通常使用和配置都比較復雜,我個人更希望實現一種“約定勝於配置”輕量級IoC框架。

實現依賴注入主要是運用C#中的反射技術,通過配置文件,把代碼的實現注入到接口中。用戶只是訪問接口,對於接口的實現一概不知,可以有效地對接口和實現進行解耦,在介紹代碼之前,先來看一下我們的配置文件:

<appSettings>
<!--依賴注入配置-->
<add key="Domain.Entity.IRepository" value="Infrastructure.Repository"/>
</appSettings>
Domain.Entity.IRepository與Infrastructure.Repository都是.NET中的程序集(dll),其中Domain.Entity.IRepository中定義了領域模型中所需要的倉儲接口,Infrastructure.Repository中定義了倉儲接口的實現。領域模型需要訪問數據的時候,並不是直接訪問ADO或者ORM,而是通過訪問Domain.Entity.IRepository中的倉儲接口,再通過依賴注入把Infrastructure.Repository中的實現注入到接口中,這樣就有效隔離了領域模型對數據實現的依賴,如果後期需要更換數據庫或ORM框架,只需要實現另一個Infrastructure.Repository,並更新依賴注入配置即可。
下面介紹輕量級依賴注入的實現方法,先貼代碼:  

public sealed class DependencyInjector
{
/// <summary>
/// 根據名稱和構造函數的參數加載相應的類
/// </summary>
/// <typeparam name="T">需要加載的類所實現的接口</typeparam>
/// <param name="className">類的名稱</param>
/// <param name="args">構造函數的參數(默認為空)</param>
/// <returns>類的接口</returns>
public static T GetClass<T>(string className, object[] args = null) where T : class
{
//獲取接口所在的命名空間
string factoryName = typeof(T).Namespace;
//通過依賴注入配置文件獲取接口實現所在的命名空間
string dllName = ConfigurationManager.AppSettings[factoryName];
//獲取類的全名
string fullClassName = dllName + "." + className;
//根據dll和類名,利用反射加載類
object classObject = Assembly.Load(dllName).CreateInstance(fullClassName, true, BindingFlags.Default, null, args, null, null); ;
return classObject as T;
}
}
代碼中的typeof(T).Namespace,其中T是接口的類型,獲取接口的命名空間以後,再通過我們的配置文件,就可以獲取類的命名空間,再加上類名,通過c#的反射機制,就可以加載類的實現。也許你會說,我們只知道接口,並不知道類名是什麼,別急,我們對該代碼進一步進行封裝:

public sealed class IoC
{
/// <summary>
/// //通過接口名稱和構造函數的參數得到實現
/// </summary>
/// <typeparam name="T">接口類型</typeparam>
/// <param name="args">構造函數的參數</param>
/// <returns>接口的實現</returns>
public static T Resolve<T>(object[] args = null) where T : class
{
//獲取類名
string className = typeof(T).Name.Substring(1);
//通過判斷fullName中是否包含`符號來判斷是否是泛型
string fullName = typeof(T).FullName;
int flag = fullName.IndexOf('`');
//如果是泛型,需要特殊處理
if (flag != -1)
{
int dot = fullName.LastIndexOf('.', flag);
//這裡去掉方法名前面的點和I
className = fullName.Substring(dot + 2);
}
return DependencyInjector.GetClass<T>(className, args);
}
}
在這裡我們就用到了上面所說的”約定勝於配置“,我們約定接口的名稱是在類名的前面加上I,並且接口和實現必須是獨立的程序集。如果類名是Helper,那麼接口的名字就必須是IHelper,我們通過去掉接口前面的I來獲得實現的類名。如果是泛型接口,還需要進行特殊的處理,這裡我們通過判斷類型的全名中是否包含”`“符號來判斷是否泛型接口。

下面舉一個使用該依賴注入的例子:

     public static Book GetById(string bookID)
{
IRepository<Book> bookRep = IoC.Resolve<IRepository<Book>>();
return bookRep.GetByKeys(bookID);
}

public int GetBookCount()
{
IBookRepository bookRep = IoC.Resolve<IBookRepository>();
return bookRep.GetCount();
}
在這裡我們是不知道接口的實現的,通過我們封裝的IoC.Resolve方法,可以把我們配置文件中的接口實現”注入到接口“中,通過這種解耦的方式,後期我可以更加靈活地對代碼進行重構。
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved