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是不是解决了这个问题呢)
依然是朦朦胧胧,继续研究!
C# IOC DI 学习的更多相关文章
- Spring 学习教程(二): IOC/DI+AOP
1. IOC / DI Spring是一个基于IOC和AOP的结构J2EE系统的框架 IOC 反转控制 是Spring的基础,Inversion Of Control 简单说就是创建对象由以前的程序员 ...
- 零基础学习java------37---------mybatis的高级映射(单表查询,多表(一对一,一对多)),逆向工程,Spring(IOC,DI,创建对象,AOP)
一. mybatis的高级映射 1 单表,字段不一致 resultType输出映射: 要求查询的字段名(数据库中表格的字段)和对应的java类型的属性名一致,数据可以完成封装映射 如果字段和jav ...
- Spring框架-IOC/DI详细学习
一.IOC/DI概念 参考博客:https://www.cnblogs.com/xdp-gacl/p/4249939.html IOC(inversion of control, 控制反转)是一种设计 ...
- 6. Laravel5学习笔记:IOC/DI的理解
介绍 IOC 控制反转 Inversion of Control 依赖关系的转移 依赖抽象而非实践 DI 依赖注入 Dependency Injection 不必自己在代码中维护对象的依赖 容器自己主 ...
- Spring4学习回顾之路02—IOC&DI
IOC&DI介绍 ●IOC:(Inversion of Control) :控制反转(反向获取资源) 其思想是反转资源获取的方向.传统的资源上查找方式要求组件向容器发起请求查找资源,作为回应, ...
- spring ioc DI 理解
下面是我从网上找来的一些大牛对spring ioc和DI的理解,希望也能让你对Spring ioc和DI的设计思想有更进一步的认识. 一.分享Iteye的开涛对Ioc的精彩讲解 Ioc—Inversi ...
- asp.net core 四 IOC&DI Autofac
其实关于IOC,DI已经有了很多的文章,但是自己在使用中还是有很多困惑,而且相信自己使用下,印象还是会比较深刻的 关于这段时间一直在学习.net core,但是这篇文章是比较重要的,也是我自己觉得学习 ...
- Spring系列(二):Spring IoC/DI的理解
这几天重新学习了一下Spring,在网上找了相关的ppt来看,当看到Spring IoC这一章节的时候,先大致浏览了一下内容,有将近50页的内容,内心窃喜~QAQ~,看完这些内容能够对IoC有更深层次 ...
- 设计模式之初识IoC/DI(六)
本篇和大家一起学习IoC和DI即控制反转和依赖注入. 当然听上去这词语非常的专业,真不知道是怎么组出来的,看上去难归看上去难,但稍微理解一下也就这么回事了. 首先我们要明白IoC/DI干嘛用的,不然别 ...
随机推荐
- .net core 操作oracle
依赖项——右键——管理NuGet程序包——浏览——输入以下内容 oracle.ManagedDataAccess.core(记得勾选包括预发行版) 在页面中加入操作数据库的方法 public IAct ...
- 太可怕了!黑客是如何攻击劫持安卓用户的DNS?
最近发现的针对Android设备的广泛路由器的DNS劫持恶意软件现在已升级为针对iOS设备以及桌面用户的功能. 被称为RoamingMantis的恶意软件最初发现在上个月劫持了互联网路由器,以散布旨在 ...
- 算法 识别有效ip地址和掩码并做统计
题目描述 请解析IP地址和对应的掩码,进行分类识别.要求按照A/B/C/D/E类地址归类,不合法的地址和掩码单独归类. 所有的IP地址划分为 A,B,C,D,E五类 A类地址1.0.0.0~126.2 ...
- STN空间变换网络
STN的主要思想是通过网络学习一个变化参数,然后计算出新图在原图上对应的坐标,再通过某种填充方法填充新图. 使得得到的新图很好的适应nn训练.可以理解为是拿来把不规范的图像变换为标准形式的图像. 网络 ...
- BestCoder Round #92 (hdu 6015 6016)
比赛链接 A题主要是map的使用,比赛的时候问了下队友,下次要记住了 #include<bits/stdc++.h> using namespace std; typedef long l ...
- nyoj 253:LK的旅行 【旋转卡壳入门】
题目链接 求平面最大点对. 找凸包 -> 根据凸包运用旋转卡壳算法求最大点对(套用kuang巨模板) 关于旋转卡壳算法 #include<bits/stdc++.h> using n ...
- map简单用法
let familyNames = []; familyNames = res.Data.map(item=> { return item.ArgText });
- vue中img图片加载中以及加载失败显示默认图片问题
加载中默认图片:主要是onload事件监听,data中定义变量 imgSrc :require('./default.png'): <div class="per-pic" ...
- 禅道安装--结合openldap
原文地址: https://blog.csdn.net/plei_yue/article/details/79075298 ldap结合禅道(需要神道不是开源版) https://www.cnblog ...
- 项目搭建(三):自定义DLL
说明:程序中有些自定义的控件类型在TestStack.White框架中没有涉及,需要引入自定义的DLL,通过鼠标点击事件处理 使用:将自定义的ClassLibrary2.dll拷贝到项目/bin/de ...