C# IOC DI 學習


之前一直不理解IOC DI,今天使勁研究了下,感覺朦朦朧朧有點感覺了,網上的這篇文章對我的有很大的啟發

http://www.cnblogs.com/jin-yuan/p/3823559.html

我仔細學習了后,按照自己的習慣從頭到尾自己敲了個實例,最后能跑起來了,感覺特高興,除了用來理解IOC和DI思想,基本沒考慮其他,但是還是貼出來記錄下吧

1,我們先實現一個簡單的讀取數據庫的功能,由於懶得真的去讀數據庫了,直接模擬了,首先是一個簡單的實體類User

namespace ConsoleApp1 {
    public class User {
        public int UserID { get; set; }
        public string UserName { get; set; }  
    }
}

2,然后模擬一個空的DBHelper,只是用來感受IOC的方便,沒有真正實現效果,因為要依賴抽象,所以下面的類基本每個都定義了一個接口

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    public interface IDBHelper {
        int Execute(string sql);
    }
    /// <summary>
    /// 模擬的DBHelper
    /// </summary>
    public class DBHelper : IDBHelper {
        private ILogHelper logHelper;
        public DBHelper(ILogHelper logHelper) {
            this.logHelper = logHelper;
        }
        public int Execute(string sql) {
            logHelper.Info("執行sql:" + sql);
            return 1;
        }
    }
}

  3,DBHelper里面有個LogHelper只是一個輸出類,模擬工具類,也是為了體驗DI的便利性

using System;

namespace ConsoleApp1 {
    public interface ILogHelper {
        void Info(string msg);
    }
    public class LogHelper : ILogHelper {
        public void Info(string msg) {
            Console.WriteLine("info: " + msg);
        }
    }
}

  4,然后是模擬的數據訪問類,里面用集合模擬數據庫

using System.Collections.Generic;

namespace ConsoleApp1 {
    public interface IUserDAL {
        int Add(User user);
        List<User> GetUsers();
    }
    public class UserDAL : IUserDAL {
        private IDBHelper dbHelper;
        public UserDAL(IDBHelper dbHelper) {
            this.dbHelper = dbHelper;
        }
        public static List<User> users = new List<User>() {
            new User(){
                UserID = 1,
                UserName ="張三"
            },
            new User(){
                UserID =2,
                UserName ="李四"
            }
        };
        public int Add(User user) {
            dbHelper.Execute("insert into User (UserID,UserName) values (3,'王五')");
            users.Add(user);
            return 1;
        }
        public List<User> GetUsers() {
            return users;
        }
    }
}

  

5,然后是業務邏輯類,在里面調用數據訪問類,以及工具類,如果是傳統的寫法,這里就要都new一下,既不美觀又很繁瑣

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApp1 {
    public interface IUserBLL {
        int Add(User user);
        List<User> GetUsers();
    }
    public class UserBLL : IUserBLL {
        private IUserDAL userDAL;
        private ILogHelper logHelper;
        public UserBLL(IUserDAL userDAL, ILogHelper logHelper) {
            this.userDAL = userDAL;
            this.logHelper = logHelper;
        }
        public int Add(User user) {
            logHelper.Info("UserBLL.Add");
            return userDAL.Add(user);
        }
        public List<User> GetUsers() {
            logHelper.Info("UserBLL.GetUsers");
            return userDAL.GetUsers();
        }
    }
}

  6,模擬是實現的DI管理類,為了好理解,我按照最簡單的方式實現的,大佬的例子這里也會考慮IOC,所以比我這復雜一些

using System;
using System.Collections.Generic;
using System.Reflection;

namespace ConsoleApp1 {
    /// <summary>
    /// 簡單模擬的DI注入類
    /// </summary>
    public class DIManager {
        /// <summary>
        /// 存放關系的容器
        /// </summary>
        private Dictionary<Type, Type> container;
        public DIManager() {
            container = new Dictionary<Type, Type>();
        }
        /// <summary>
        /// 將接口和實現類關聯綁定起來
        /// </summary> 
        public void Bind<K, V>() {
            container.Add(typeof(K), typeof(V));
        }
        /// <summary>
        /// 獲取泛型類型的對象
        /// </summary> 
        public T Get<T>() {
            return (T)Injection(typeof(T));
        }
        /// <summary>
        /// 對傳入的類型進行構造函數注入
        /// </summary> 
        private object Injection(Type type) {
            object instance = null;
            foreach (ConstructorInfo ci in type.GetConstructors()) {  //循環類的構造函數
                if (ci.GetParameters().Length > 0) {
                    List<object> parameters = new List<object>();
                    foreach (ParameterInfo pi in ci.GetParameters()) { //循環構造函數的參數
                        if (container.ContainsKey(pi.ParameterType)) {
                            parameters.Add(Injection(container[pi.ParameterType])); //遞歸實現所有相關注冊過的類型的構造函數注入
                        }
                    }
                    instance = CreateInstance(type, parameters.ToArray());
                    break;
                }
            }
            if (instance == null) {
                instance = CreateInstance(type);
            }
            return instance;
        }
        /// <summary>
        /// 創建對象
        /// </summary> 
        private object CreateInstance(Type type, params object[] args) {
            return Activator.CreateInstance(type, args);
        }
    }
}

  7,最后是Program的使用,我們只要在程序運行的時候,注冊綁定需要用到的抽象和實現,然后就能直接通過Get獲取實例,並且這些實例中的構造函數都會自動創建注入相關的對象,這樣就不用我們各種重復的new了

using System;

namespace ConsoleApp1 {
    class Program {
        static void Main(string[] args) {
            DIManager manager = new DIManager();
            manager.Bind<IUserBLL, UserBLL>();
            manager.Bind<IUserDAL, UserDAL>();
            manager.Bind<IDBHelper, DBHelper>();
            manager.Bind<ILogHelper, LogHelper>();
            IUserBLL userBLL = manager.Get<UserBLL>();
            User user = new User() { UserID = 3, UserName = "王五" };
            Console.WriteLine(userBLL.Add(user));
            foreach (var u in userBLL.GetUsers()) {
                Console.WriteLine(u.UserName);
            }
            Console.ReadKey();
        }
    }
}

  總結:IOC是控制反轉,就是把底層的耦合拋到外面,類的內部只依賴抽象,代碼里定義的那么多接口就是實現這個效果,但是即使我們把控制拋到了外面,這些對象還是得創建啊,所以就用到了DI(依賴注入)上面的類里面都是通過構造函數來獲取我們要用到得對象,我們依賴這些對象,對象哪來的?答,注冊接口和類得關系,然后在代碼里自動生成的,你可以觀察DIManager的Injection,大致就是根據類的類型獲取構造函數信息,創建構造函數的參數類型的對象,然后根據構造函數以及參數對象創建本身的對象來達到注入的效果,最后遞歸注入所有相關的構造函數(這里貌似性能浪費啊,假如我只使用UserBLL的一個方法,而這個方法有咩有真正的使用UserDAL和LogHelper,那么程序就創建了白創建了2個用不到的對象,不知道真正的DI是不是解決了這個問題呢)

依然是朦朦朧朧,繼續研究!


免責聲明!

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



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