之前一直不理解IOC DI,今天使劲研究了下,感觉朦朦胧胧有点感觉了,网上的这篇文章对我的有很大的启发

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

我仔细学习了后,按照自己的习惯从头到尾自己敲了个实例,最后能跑起来了,感觉特高兴,除了用来理解IOC和DI思想,基本没考虑其他,但是还是贴出来记录下吧

1,我们先实现一个简单的读取数据库的功能,由于懒得真的去读数据库了,直接模拟了,首先是一个简单的实体类User

  1. namespace ConsoleApp1 {
  2. public class User {
  3. public int UserID { get; set; }
  4. public string UserName { get; set; }
  5. }
  6. }

2,然后模拟一个空的DBHelper,只是用来感受IOC的方便,没有真正实现效果,因为要依赖抽象,所以下面的类基本每个都定义了一个接口

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace ConsoleApp1 {
  8. public interface IDBHelper {
  9. int Execute(string sql);
  10. }
  11. /// <summary>
  12. /// 模拟的DBHelper
  13. /// </summary>
  14. public class DBHelper : IDBHelper {
  15. private ILogHelper logHelper;
  16. public DBHelper(ILogHelper logHelper) {
  17. this.logHelper = logHelper;
  18. }
  19. public int Execute(string sql) {
  20. logHelper.Info("执行sql:" + sql);
  21. return 1;
  22. }
  23. }
  24. }

  3,DBHelper里面有个LogHelper只是一个输出类,模拟工具类,也是为了体验DI的便利性

  1. using System;
  2.  
  3. namespace ConsoleApp1 {
  4. public interface ILogHelper {
  5. void Info(string msg);
  6. }
  7. public class LogHelper : ILogHelper {
  8. public void Info(string msg) {
  9. Console.WriteLine("info: " + msg);
  10. }
  11. }
  12. }

  4,然后是模拟的数据访问类,里面用集合模拟数据库

  1. using System.Collections.Generic;
  2.  
  3. namespace ConsoleApp1 {
  4. public interface IUserDAL {
  5. int Add(User user);
  6. List<User> GetUsers();
  7. }
  8. public class UserDAL : IUserDAL {
  9. private IDBHelper dbHelper;
  10. public UserDAL(IDBHelper dbHelper) {
  11. this.dbHelper = dbHelper;
  12. }
  13. public static List<User> users = new List<User>() {
  14. new User(){
  15. UserID = 1,
  16. UserName ="张三"
  17. },
  18. new User(){
  19. UserID =2,
  20. UserName ="李四"
  21. }
  22. };
  23. public int Add(User user) {
  24. dbHelper.Execute("insert into User (UserID,UserName) values (3,'王五')");
  25. users.Add(user);
  26. return 1;
  27. }
  28. public List<User> GetUsers() {
  29. return users;
  30. }
  31. }
  32. }

  

5,然后是业务逻辑类,在里面调用数据访问类,以及工具类,如果是传统的写法,这里就要都new一下,既不美观又很繁琐

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text;
  5. using System.Threading.Tasks;
  6.  
  7. namespace ConsoleApp1 {
  8. public interface IUserBLL {
  9. int Add(User user);
  10. List<User> GetUsers();
  11. }
  12. public class UserBLL : IUserBLL {
  13. private IUserDAL userDAL;
  14. private ILogHelper logHelper;
  15. public UserBLL(IUserDAL userDAL, ILogHelper logHelper) {
  16. this.userDAL = userDAL;
  17. this.logHelper = logHelper;
  18. }
  19. public int Add(User user) {
  20. logHelper.Info("UserBLL.Add");
  21. return userDAL.Add(user);
  22. }
  23. public List<User> GetUsers() {
  24. logHelper.Info("UserBLL.GetUsers");
  25. return userDAL.GetUsers();
  26. }
  27. }
  28. }

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

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Reflection;
  4.  
  5. namespace ConsoleApp1 {
  6. /// <summary>
  7. /// 简单模拟的DI注入类
  8. /// </summary>
  9. public class DIManager {
  10. /// <summary>
  11. /// 存放关系的容器
  12. /// </summary>
  13. private Dictionary<Type, Type> container;
  14. public DIManager() {
  15. container = new Dictionary<Type, Type>();
  16. }
  17. /// <summary>
  18. /// 将接口和实现类关联绑定起来
  19. /// </summary>
  20. public void Bind<K, V>() {
  21. container.Add(typeof(K), typeof(V));
  22. }
  23. /// <summary>
  24. /// 获取泛型类型的对象
  25. /// </summary>
  26. public T Get<T>() {
  27. return (T)Injection(typeof(T));
  28. }
  29. /// <summary>
  30. /// 对传入的类型进行构造函数注入
  31. /// </summary>
  32. private object Injection(Type type) {
  33. object instance = null;
  34. foreach (ConstructorInfo ci in type.GetConstructors()) { //循环类的构造函数
  35. if (ci.GetParameters().Length > 0) {
  36. List<object> parameters = new List<object>();
  37. foreach (ParameterInfo pi in ci.GetParameters()) { //循环构造函数的参数
  38. if (container.ContainsKey(pi.ParameterType)) {
  39. parameters.Add(Injection(container[pi.ParameterType])); //递归实现所有相关注册过的类型的构造函数注入
  40. }
  41. }
  42. instance = CreateInstance(type, parameters.ToArray());
  43. break;
  44. }
  45. }
  46. if (instance == null) {
  47. instance = CreateInstance(type);
  48. }
  49. return instance;
  50. }
  51. /// <summary>
  52. /// 创建对象
  53. /// </summary>
  54. private object CreateInstance(Type type, params object[] args) {
  55. return Activator.CreateInstance(type, args);
  56. }
  57. }
  58. }

  7,最后是Program的使用,我们只要在程序运行的时候,注册绑定需要用到的抽象和实现,然后就能直接通过Get获取实例,并且这些实例中的构造函数都会自动创建注入相关的对象,这样就不用我们各种重复的new了

  1. using System;
  2.  
  3. namespace ConsoleApp1 {
  4. class Program {
  5. static void Main(string[] args) {
  6. DIManager manager = new DIManager();
  7. manager.Bind<IUserBLL, UserBLL>();
  8. manager.Bind<IUserDAL, UserDAL>();
  9. manager.Bind<IDBHelper, DBHelper>();
  10. manager.Bind<ILogHelper, LogHelper>();
  11. IUserBLL userBLL = manager.Get<UserBLL>();
  12. User user = new User() { UserID = 3, UserName = "王五" };
  13. Console.WriteLine(userBLL.Add(user));
  14. foreach (var u in userBLL.GetUsers()) {
  15. Console.WriteLine(u.UserName);
  16. }
  17. Console.ReadKey();
  18. }
  19. }
  20. }

  总结:IOC是控制反转,就是把底层的耦合抛到外面,类的内部只依赖抽象,代码里定义的那么多接口就是实现这个效果,但是即使我们把控制抛到了外面,这些对象还是得创建啊,所以就用到了DI(依赖注入)上面的类里面都是通过构造函数来获取我们要用到得对象,我们依赖这些对象,对象哪来的?答,注册接口和类得关系,然后在代码里自动生成的,你可以观察DIManager的Injection,大致就是根据类的类型获取构造函数信息,创建构造函数的参数类型的对象,然后根据构造函数以及参数对象创建本身的对象来达到注入的效果,最后递归注入所有相关的构造函数(这里貌似性能浪费啊,假如我只使用UserBLL的一个方法,而这个方法有咩有真正的使用UserDAL和LogHelper,那么程序就创建了白创建了2个用不到的对象,不知道真正的DI是不是解决了这个问题呢)

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

C# IOC DI 学习的更多相关文章

  1. Spring 学习教程(二): IOC/DI+AOP

    1. IOC / DI Spring是一个基于IOC和AOP的结构J2EE系统的框架 IOC 反转控制 是Spring的基础,Inversion Of Control 简单说就是创建对象由以前的程序员 ...

  2. 零基础学习java------37---------mybatis的高级映射(单表查询,多表(一对一,一对多)),逆向工程,Spring(IOC,DI,创建对象,AOP)

    一.  mybatis的高级映射 1  单表,字段不一致 resultType输出映射: 要求查询的字段名(数据库中表格的字段)和对应的java类型的属性名一致,数据可以完成封装映射 如果字段和jav ...

  3. Spring框架-IOC/DI详细学习

    一.IOC/DI概念 参考博客:https://www.cnblogs.com/xdp-gacl/p/4249939.html IOC(inversion of control, 控制反转)是一种设计 ...

  4. 6. Laravel5学习笔记:IOC/DI的理解

    介绍 IOC 控制反转 Inversion of Control 依赖关系的转移 依赖抽象而非实践 DI 依赖注入 Dependency Injection 不必自己在代码中维护对象的依赖 容器自己主 ...

  5. Spring4学习回顾之路02—IOC&DI

    IOC&DI介绍 ●IOC:(Inversion of Control) :控制反转(反向获取资源) 其思想是反转资源获取的方向.传统的资源上查找方式要求组件向容器发起请求查找资源,作为回应, ...

  6. spring ioc DI 理解

    下面是我从网上找来的一些大牛对spring ioc和DI的理解,希望也能让你对Spring ioc和DI的设计思想有更进一步的认识. 一.分享Iteye的开涛对Ioc的精彩讲解 Ioc—Inversi ...

  7. asp.net core 四 IOC&DI Autofac

    其实关于IOC,DI已经有了很多的文章,但是自己在使用中还是有很多困惑,而且相信自己使用下,印象还是会比较深刻的 关于这段时间一直在学习.net core,但是这篇文章是比较重要的,也是我自己觉得学习 ...

  8. Spring系列(二):Spring IoC/DI的理解

    这几天重新学习了一下Spring,在网上找了相关的ppt来看,当看到Spring IoC这一章节的时候,先大致浏览了一下内容,有将近50页的内容,内心窃喜~QAQ~,看完这些内容能够对IoC有更深层次 ...

  9. 设计模式之初识IoC/DI(六)

    本篇和大家一起学习IoC和DI即控制反转和依赖注入. 当然听上去这词语非常的专业,真不知道是怎么组出来的,看上去难归看上去难,但稍微理解一下也就这么回事了. 首先我们要明白IoC/DI干嘛用的,不然别 ...

随机推荐

  1. Synchronized和ReentranLock的比较

    并发编程最容易遇到的问题就是就是安全问题,因此解决方式有两种 使用同步方法或同步代码块(Synchronized关键字) 使用锁机制(ReentranLock) 同步方法和同步代码块(Synchron ...

  2. 获取配置文件yml的@ConfigurationProperties和@Value的区别

    首先,配置文件的事,我没讲properties,这个写中文的时候,会有乱码,需要去Idea里面设置一下编码格式为UTF-8 还有,我们的类和配置文件直接关联,我用的是ConfigurationProp ...

  3. AGC001[BCDE] 题解

    A没意思 F太难 所以大概近期的AGC题解都是BCDE的 然后特殊情况再说 开始刷AGC的原因就是计数太差 没有脑子 好几个学长都推荐的AGC所以就开始刷了 = = 大概两天三篇的速度?[可能也就最开 ...

  4. SQL必知必会学习笔记

    2.5  select SELECT       要返回的列或表达式     是FROM          从中检索数据的表        仅在从表选择数据时使用WHERE        行级过滤   ...

  5. centos 6.5 解压 tar.gz

    只查看 tar.gz 文件内容而不解压 tar -tvf filename.tar.gz 解压为 tar 文件 gzip -d filename.tar.gz 解压为文件或目录 tar xvf fil ...

  6. selenium环境搭建,浏览器驱动安装

    一安装Python: 1.下载Phtyon地址:https://www.python.org/getit/ 2.安装python会默认安装两个基础包setuptools,pip   也可以手动安装: ...

  7. CentOS6.5下安装jdk配置环境变量错误问题:

    CentOS6.5下安装jdk,使用gedit /etc/profile  配置环境变量为如下: export JAVA_HOME=/usr/soft/jdk7export PATH=$JAVA_HO ...

  8. 四轴PID思路整理

    参考资料: https://blog.csdn.net/nemol1990/article/details/45131603 https://blog.csdn.net/qq_27114397/art ...

  9. mysql 8.0版本下载安装以及默认密码修改

    1. 下载 去mysql官网下载地址进行下载,选择需要的安装包 可以直接跳过登录进行下载 ps:我是先注册账号下载的,注册时遇到一个坑,就是在chrome75版本无法选择省市,不选择又不让注册. 可以 ...

  10. VMware linux 克隆机的配置

    从另一台虚拟机克隆完后的一些配置 编辑eth0的配置文件: [root@wen data01:4]# vim /etc/sysconfig/network-scripts/ifcfg-eth0 删除 ...