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

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

【沒有接口】數據庫

新增Model 層,LoginUser 當前登陸人。無接口的怎樣用IOC 建立對象。代碼以下ide

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 ,繼承 IAnalysethis

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

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

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

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 層增長顯示代碼code

/// <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來區分子類型。修改代碼htm

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

(我的以爲方法注入很雞肋,其實就是屬性注入)

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

 【源碼下載】

相關文章
相關標籤/搜索