我在項目中運用 IOC(依賴注入)--實戰篇


上一篇《我在項目中運用 IOC(依賴注入)--入門篇》只是簡單的使用 IOC。實際項目使用 IOC 的情景復雜多了,比如說,構造函數有多個參數,有多個類繼承同一個接口... Unity都有解決方法。首先回顧一下入門篇的項目需求:項目中數據統計功能,它下面有三種不同的統計類型,需要與數據庫交互,然后展示到頁面,在這篇中我們接着這個需求繼續擴充。

【沒有接口】

新增Model 層,LoginUser 當前登錄人。無接口的怎樣用IOC 創建對象。代碼如下

Model.LoginUser loginUser = container.Resolve<Model.LoginUser>();

【多個子類】

DAL 層 新增ShowResult2 方法

public class Analyse:IDAL.IAnalyse
{
public void ShowResult()
{
Console.WriteLine("分析底層數據庫交互");
}

public void ShowResult2()
{
Console.WriteLine("這是B類分析底層數據庫交互");
}
}

BLL層 新增 AnalyseB ,繼承 IAnalyse

 public class AnalyseB:IBLL.IAnalyse
    {
        ////使用依賴注入
        [Dependency]
        public IDAL.IAnalyse dal { get; set; }

        public void ShowResult()
        {
            dal.ShowResult2();
        }
    }

按照入門篇的步驟,需要在core 層 DependencyRegister 修改 DependencyRegisterContainer 方法

public static IUnityContainer DependencyRegisterContainer()
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>()
                     .RegisterType<IDAL.IAnalyse, DAL.Analyse>()
                     .RegisterType<IBLL.IAnalyse, BLL.AnalyseB>();
            return container;
        }

我們發現IBLL.IAnalyse被兩個類繼承,所以在 IOC 容器中注入了兩次。這樣寫能區分開嗎?我們先在UI 層增加顯示代碼

/// <summary>
        /// 多個類繼承同一個接口
        /// </summary>
        private static void IOCMethod4()
        {
            IUnityContainer container = DependencyRegister.DependencyRegisterContainer();
            IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>();
            bll.ShowResult();
        }

運行程序,發現每次只會出現 AnalyseB 類的結果。即 IAnalyse=最后注冊的類型 。Unity 的 RegisterType 方法有個參數string name。用key來區分子類型。修改代碼

//core 層
public static IUnityContainer DependencyRegisterContainer()
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>()
                     .RegisterType<IDAL.IAnalyse, DAL.Analyse>()
                     .RegisterType<IBLL.IAnalyse, BLL.AnalyseB>("Analyse-B");
            return container;
        }

//// UI 層
        private static void IOCMethod4()
        {
            IUnityContainer container = DependencyRegister.DependencyRegisterContainer();
            IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>("Analyse-B");
            bll.ShowResult();
        }

////同時運行 IOCMethod2() 和 IOCMethod4()

結果

這樣就是實現了子類多個的 IOC 容器注冊。(注意,key一定要區分大小寫)

 【帶參的構造函數】

Web程序與數據庫交互的時候,需要從前台獲取查詢條件,我在 AnalyseB 中寫了一個帶有 string 類型的構造函數。代碼如下

 public class AnalyseB:IBLL.IAnalyse
    {
        public string StrWhere { get; set; }

        /// <summary>
        /// 查詢條件的構造函數
        /// </summary>
        /// <param name="strWhere"></param>
        public AnalyseB(string strWhere)
        {
            this.StrWhere = strWhere;
        }

        ////使用依賴注入
        [Dependency]
        public IDAL.IAnalyse dal { get; set; }
public void ShowResult() { dal.ShowResult2(StrWhere); } }
//// 修改 core 層 容器注冊方法 public static IUnityContainer DependencyRegisterContainer() { IUnityContainer container = new UnityContainer(); container.RegisterType<IBLL.IAnalyse, BLL.Analyse>() .RegisterType<IDAL.IAnalyse, DAL.Analyse>() .RegisterType<IBLL.IAnalyse, BLL.AnalyseB>("Analyse-B", (new InjectionConstructor(typeof(string)))); return container; } ////UI 層調用代碼如下 private static void IOCMethod4() { IUnityContainer container = DependencyRegister.DependencyRegisterContainer(); IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>("Analyse-B", new ParameterOverride("strWhere", " WHERE 1=1 ")); bll.ShowResult(); }

 AnalyseB 構造函數帶有string 類型的參數,在 容器注冊的時候,需要注冊 參數的類型  new InjectionConstructor(typeof(string),typeof(param2),...) (這里也可以是常量)。調用時用ParameterOverride(構造函數參數名,參數值) 來重新給參數賦值。

如果參數是其它類型又怎么辦。例如數據以表格形式呈現時,需要分頁。我在BLL 層加了一個分頁接口。修改代碼

////新增分頁接口
public interface IPager
    {
        string GetPager();
    }

public class AnalysePager : IBLL.IPager
    {
        public string GetPager()
        {
            return "數據已分頁";
        }
    }

public class AnalyseB:IBLL.IAnalyse
    {
        public string StrWhere { get; set; }
        public IBLL.IPager Pager { get; set; }

        public AnalyseB(IBLL.IPager pager, string strWhere)
        {
            this.Pager = pager;
            this.StrWhere = strWhere  + pager.GetPager();
        }

        ////使用依賴注入
        [Dependency]
        public IDAL.IAnalyse dal { get; set; }

        
        public void ShowResult()
        {
            dal.ShowResult2(StrWhere);
        }
    }

////修改core層 方法
 public class DependencyRegister
    {
        public static IUnityContainer DependencyRegisterContainer()
        {
            IUnityContainer container = new UnityContainer(); 
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>()
                     .RegisterType<IDAL.IAnalyse, DAL.Analyse>()
                     .RegisterType<IBLL.IPager,BLL.AnalysePager>()
                     .RegisterType<IBLL.IAnalyse, BLL.AnalyseB>("Analyse-B", (new InjectionConstructor(typeof(IBLL.IPager) , typeof(string))));
            return container;
        }
    }

////UI 層代碼不變

運行結果:

【屬性注入】

修改一下構造函數,把參數 IPager 提成屬性。 代碼如下

public class AnalyseB:IBLL.IAnalyse
    {
        public string StrWhere { get; set; }

        public IBLL.IPager Pager { get; set; }

        /// <summary>
        /// 查詢條件的構造函數
        /// </summary>
        /// <param name="strWhere"></param>
        public AnalyseB(IBLL.IPager pager, string strWhere)
        {
            this.Pager = pager;
            this.StrWhere = strWhere  + pager.GetPager();
        }
        public AnalyseB(string strWhere)
        {
            this.StrWhere = strWhere;
        }

        ////使用依賴注入
        //[Dependency]
        public IDAL.IAnalyse dal { get; set; }

        
        public void ShowResult()
        {
            StrWhere += Pager.GetPager();
            dal.ShowResult2(StrWhere);
        }

//// core 
 public static IUnityContainer DependencyRegisterContainer()
        {
            IUnityContainer container = new UnityContainer();
            container.RegisterType<IBLL.IAnalyse, BLL.Analyse>()
                     .RegisterType<IDAL.IAnalyse, DAL.Analyse>()
                     .RegisterType<IBLL.IPager, BLL.AnalysePager>()
                //.RegisterType<IBLL.IAnalyse, BLL.AnalyseB>("Analyse-C", (new InjectionConstructor(typeof(IBLL.IPager) , typeof(string))));
                     .RegisterType<IBLL.IAnalyse, BLL.AnalyseB>("Analyse-D", new InjectionMember[]
                         {
                             new InjectionConstructor(typeof (string)),
                             new InjectionProperty("Pager"), 
                             new InjectionProperty("dal"), 
                         });
            return container;
        }

自己在實際使用過程總結了幾點:

1.使用屬性注入,屬性不能再構造函數中使用,否則會報為實例化對象異常。(關於這點自己持懷疑態度,有可能是自己不正確的使用造成的。希望和大家討論

2.BLL.AnalyseB 本身有個屬性 dal. 如果使用屬性注入,則所有屬性都須加入 InjectionMember[] .

3.最好使用構造注入。

(以上三點是在項目使用過程中,自己總結出來。非權威,非標准,有不對的地方希望大家指出。`(*∩_∩*)′)

 

【方法注入】

除開構造注入,屬性注入,還有方法注入。使用與屬性注入差不多。方法注入尚沒有在實際項目中應用過,下面例子是參考其它兩種注入方法寫的

////修改此類,增加字段_pager 和 方法 SetPager
public class AnalyseB:IBLL.IAnalyse
    {
        public string StrWhere { get; set; }

        public IBLL.IPager Pager { get; set; }

        public IBLL.IPager _pager;

        public void SetPager(IBLL.IPager pager)
        {
            this._pager = pager;
        }



        /// <summary>
        /// 查詢條件的構造函數
        /// </summary>
        /// <param name="strWhere"></param>
        public AnalyseB(IBLL.IPager pager, string strWhere)
        {
           this.Pager = pager;
            this.StrWhere = strWhere + pager.GetPager();
        }

        public AnalyseB(string strWhere)
        {
            this.StrWhere = strWhere;
        }

        ////使用依賴注入
        [Dependency]
        public IDAL.IAnalyse dal { get; set; }


        public void ShowResult()
        {
            //StrWhere += Pager.GetPager();
            StrWhere += this._pager.GetPager();
            dal.ShowResult2(StrWhere);
        }

////增加core層的注入方式
container..RegisterType<IBLL.IAnalyse, BLL.AnalyseB>("Analyse-E", new InjectionMember[]
                         {
                             new InjectionConstructor(typeof (string)),
                             new InjectionMethod("SetPager",container.Resolve<IBLL.IPager>()),
                         });

////UI 層調用
/// <summary>
        /// 方法注入
        /// </summary>
        public static void IOCMethod6()
        {
            IUnityContainer container = DependencyRegister.DependencyRegisterContainer();
            IBLL.IAnalyse bll = container.Resolve<IBLL.IAnalyse>("Analyse-E",
                                                                 new ParameterOverride("strWhere", " WHERE 1=1 "));
            bll.ShowResult();
        }

(個人覺得方法注入很雞肋,其實就是屬性注入)

以上是我在項目運用過程中總結出來的一些心得,尚有許多不足的地方,先拋磚引玉,與大家共同討論,共同學習。

 【源碼下載】


免責聲明!

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



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