• 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是不是解决了这个问题呢)

    依然是朦朦胧胧,继续研究!
  • 相关阅读:
    能飞英语学习软件学习实践
    英语学习方式总结与实践
    Hello World
    centos 7.6中搭建samba共享服务
    PHP漏洞全解(一)PHP网站的安全性问题
    MySQL查询语句练习题
    在PHP中使用CURL实现GET和POST请求的方法
    js数组的操作大全
    php四种基础算法:冒泡,选择,插入和快速排序法
    Linux查看端口使用状态及启动
  • 原文地址:https://www.cnblogs.com/luludongxu/p/10672468.html
Copyright © 2020-2023  润新知