博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C# IOC DI 学习
阅读量:5875 次
发布时间:2019-06-19

本文共 5760 字,大约阅读时间需要 19 分钟。

之前一直不理解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);    }    ///     /// 模拟的DBHelper    ///     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
GetUsers(); } public class UserDAL : IUserDAL { private IDBHelper dbHelper; public UserDAL(IDBHelper dbHelper) { this.dbHelper = dbHelper; } public static List
users = new List
() { 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
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
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
GetUsers() { logHelper.Info("UserBLL.GetUsers"); return userDAL.GetUsers(); } }}

  6,模拟是实现的DI管理类,为了好理解,我按照最简单的方式实现的,大佬的例子这里也会考虑IOC,所以比我这复杂一些

using System;using System.Collections.Generic;using System.Reflection;namespace ConsoleApp1 {    ///     /// 简单模拟的DI注入类    ///     public class DIManager {        ///         /// 存放关系的容器        ///         private Dictionary
container; public DIManager() { container = new Dictionary
(); } ///
/// 将接口和实现类关联绑定起来 /// public void Bind
() { container.Add(typeof(K), typeof(V)); } ///
/// 获取泛型类型的对象 /// public T Get
() { return (T)Injection(typeof(T)); } ///
/// 对传入的类型进行构造函数注入 /// private object Injection(Type type) { object instance = null; foreach (ConstructorInfo ci in type.GetConstructors()) { //循环类的构造函数 if (ci.GetParameters().Length > 0) { List
parameters = new List(); 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; } /// /// 创建对象 /// 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
(); manager.Bind
(); manager.Bind
(); manager.Bind
(); IUserBLL userBLL = manager.Get
(); 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是不是解决了这个问题呢)

依然是朦朦胧胧,继续研究!

转载于:https://www.cnblogs.com/luludongxu/p/10672468.html

你可能感兴趣的文章
007-Shell test 命令,[],[[]]
查看>>
关于Linux系统使用遇到的问题-1:vi 打开只读(readonly)文件如何退出保存?
查看>>
pandas 按照某一列进行排序
查看>>
在WPF中如何使用RelativeSource绑定
查看>>
Map的深浅拷贝的探究
查看>>
XSLT语法 在.net中使用XSLT转换xml文档示例
查看>>
如何将lotus 通讯簿导入到outlook 2003中
查看>>
WinForm 应用程序中开启新的进程及控制
查看>>
前端工程师的职业发展路线在哪?
查看>>
IOS 内存警告 Memory warning level
查看>>
[转]PAC Manager: Ubuntu 上强大的 SSH 帐号管理工具,可取代 SecureCRT_Miracle_百度空间...
查看>>
顺序容器 (2)string类型操作
查看>>
转载:我最近的研究成果(IGeometry.Project and IGeometry.SpatialReference)
查看>>
提示框
查看>>
HDOJ1233 畅通工程之一(最小生成树-Kruscal)
查看>>
14Spring_AOP编程(AspectJ)_环绕通知
查看>>
PHP之打开文件
查看>>
iOS - OC SQLite 数据库存储
查看>>
PHP-mysqllib和mysqlnd
查看>>
Redis常用命令
查看>>