目录
[1. IoC容器对象项目结构的影响](#1. IoC容器对象项目结构的影响)
[2. IoC容器中的对象依赖注入](#2. IoC容器中的对象依赖注入)
[3. IoC概念理解与自定义IoC容器](#3. IoC概念理解与自定义IoC容器)
[4. 自定义IoC容器的基本控制逻辑](#4. 自定义IoC容器的基本控制逻辑)
[5. IOC瞬态模式与单例模式逻辑整合](#5. IOC瞬态模式与单例模式逻辑整合)
[6. 无限层级的依赖注入逻辑处理](#6. 无限层级的依赖注入逻辑处理)
[7. 属性注入逻辑处理](#7. 属性注入逻辑处理)
[8. 单接口多实现注入逻辑处理](#8. 单接口多实现注入逻辑处理)
1. IoC容器对象项目结构的影响
IoC容器的作用是将对象的创建和依赖关系的管理从代码中解耦出来,交给容器来处理。通过这种方式,项目的结构会更加清晰和模块化。
代码体现:
在你的代码中,MyIoc
类是一个自定义的IoC容器。它通过 _instenceDic
字典来管理对象的注册和实例化。这种设计使得对象的创建和依赖关系不再硬编码在业务逻辑中,而是由容器统一管理。
- 解耦 :对象的创建和依赖关系由
MyIoc
管理,业务代码只需要通过Resolve
方法获取实例,无需关心对象的创建过程。 - 模块化:通过接口和抽象类定义依赖关系,具体的实现类由容器注入,增强了代码的模块化。
2. IoC容器中的对象依赖注入
依赖注入(DI)是IoC的一种实现方式。通过依赖注入,对象的依赖关系由外部容器在运行时注入,而不是在对象内部硬编码。
代码体现:
在 MyIoc
类中,依赖注入主要通过以下方式实现:
- 构造函数注入 :在
CreateInstence
方法中,通过反射获取构造函数的参数,并从容器中解析这些参数,最终创建对象实例。 - 属性注入 :在
CreateInstence
方法中,通过反射获取对象的属性,并根据属性的标记(如DependyAttribute
)从容器中解析并注入依赖。
例如:
- 构造函数注入:
cs
// 构造函数注入
ConstructorInfo[] cis = _instenceDic[key].ObjectType.GetConstructors();
ParameterInfo[] cpis = cis[0].GetParameters();
List<object> objects = new List<object>();
foreach (ParameterInfo cpi in cpis)
{
string paramTypeKey = cpi.ParameterType.FullName;
if (_instenceDic.ContainsKey(paramTypeKey))
{
objects.Add(_instenceDic[paramTypeKey].Instence);
}
}
var obj = Activator.CreateInstance(_instenceDic[key].ObjectType, objects.ToArray());
- 属性注入:
cs
PropertyInfo[] pis = type.GetProperties();
foreach (var pi in pis)
{
if (pi.IsDefined(typeof(DependyAttribute), false))
{
var attr = pi.GetCustomAttribute<DependyAttribute>();
string paramTypeKey = pi.PropertyType.FullName + (string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token);
if (_instenceDic.ContainsKey(paramTypeKey))
{
pi.SetValue(obj, _instenceDic[paramTypeKey].Instence);
}
}
}
3. IoC概念理解与自定义IoC容器
IoC的核心思想是将对象的创建和依赖关系的管理交给外部容器,而不是在代码中硬编码。通过这种方式,代码的灵活性和可维护性得到了提升。
代码体现:
MyIoc
是一个自定义的IoC容器,它通过字典 _instenceDic
来存储注册的类型和实例。每个注册的类型都包含一个 InstenceModel
对象,该对象记录了类型的元数据(如是否为单例)以及实例本身。
- 注册类型 :通过
Register
和RegisterSingle
方法将类型注册到容器中。 - 解析实例 :通过
Resolve
方法从容器中获取实例。
4. 自定义IoC容器的基本控制逻辑
MyIoc
类的基本控制逻辑如下:
- 注册类型:
-
Register<T>()
:注册瞬时对象(每次请求都创建新实例)。RegisterSingle<T>()
:注册单例对象(整个应用程序生命周期内只创建一个实例)。Register<TFrom, TTo>()
:注册接口和实现类的关系。
- 解析实例:
-
Resolve<T>()
:从容器中获取实例。如果注册的类型是单例模式,则返回同一个实例;如果是瞬时模式,则每次返回新的实例。
- 依赖注入:
-
- 在创建实例时,
CreateInstence
方法会递归地解析构造函数参数和属性依赖,确保所有依赖都被正确注入。
- 在创建实例时,
5. IOC瞬态模式与单例模式逻辑整合
在 MyIoc
中,瞬态模式和单例模式的逻辑通过 InstenceModel
中的 IsSinglton
属性进行区分:
- 瞬态模式 :每次调用
Resolve
时,都会创建一个新的实例。 - 单例模式 :只有在第一次调用
Resolve
时创建实例,后续调用都返回同一个实例。
代码体现:
cs
if (_instenceDic[key].IsSinglton)
{
if (_instenceDic[key].Instence is null)
{
lock (_instanceLock)
{
if (_instenceDic[key].Instence is null)
{
return (T)CreateInstence(key, typeof(T));
}
return (T)_instenceDic[key].Instence;
}
}
return (T)_instenceDic[key].Instence;
}
else
{
// 在瞬时模式下,每次都调用
return (T)CreateInstence(key, typeof(T));
}
6. 无限层级的依赖注入逻辑处理
在 CreateInstence
方法中,通过递归调用 CreateInstence
来处理无限层级的依赖注入。当某个对象的构造函数参数或属性依赖其他对象时,容器会递归地解析这些依赖,直到所有依赖都被满足。
代码体现:
cs
if (_instenceDic.ContainsKey(paramTypeKey))
{
if (_instenceDic[paramTypeKey].IsSinglton)
{
if (_instenceDic[paramTypeKey].Instence is null)
{
_instenceDic[paramTypeKey].Instence = CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
}
}
else
{
_instenceDic[paramTypeKey].Instence = CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
}
objects.Add(_instenceDic[paramTypeKey].Instence);
}
7. 属性注入逻辑处理
在 CreateInstence
方法中,通过反射获取对象的属性,并根据属性的标记(如 DependyAttribute
)从容器中解析并注入依赖。
代码体现:
cs
PropertyInfo[] pis = type.GetProperties();
foreach (var pi in pis)
{
if (pi.IsDefined(typeof(DependyAttribute), false))
{
var attr = pi.GetCustomAttribute<DependyAttribute>();
string paramTypeKey = pi.PropertyType.FullName + (string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token);
if (_instenceDic.ContainsKey(paramTypeKey))
{
pi.SetValue(obj, _instenceDic[paramTypeKey].Instence);
}
}
}
8. 单接口多实现注入逻辑处理
在 MyIoc
中,通过 Register<TFrom, TTo>
和 RegisterSingle<TFrom, TTo>
方法支持单接口多实现的注入。通过 token
参数,可以为同一个接口的不同实现指定不同的标识符,从而在解析时区分不同的实现。
代码体现:
cs
public void Register<TFrom, TTo>(string token = "") where TTo : TFrom
{
string key = typeof(TFrom).FullName + (String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);
_instenceDic.Add(key, new InstenceModel { ObjectType = typeof(TTo), IsSinglton = false });
}
在解析时,可以通过指定 token
来获取不同的实现:
cs
var serviceA = ioc.Resolve<IService>("A");
var serviceB = ioc.Resolve<IService>("B");
9.完整代码
cs
using System;
using System.Collections.Generic;
using System.Reflection;
namespace MvvmLightLesson.Base
{
public class MyIoc
{
private static readonly object _instanceLock = new object();
private static MyIoc instance;
private Dictionary<string, InstenceModel> _instenceDic = new Dictionary<string, InstenceModel>();
private MyIoc()
{ }
public static MyIoc Default
{
get
{
if (instance == null)
{
lock (_instanceLock)
{
if (instance == null)
{
instance = new MyIoc();
}
}
}
return instance;
}
}
// 瞬时状态
public void Register<T>()
{
_instenceDic.Add(
typeof(T).FullName!,
new InstenceModel { ObjectType = typeof(T), IsSinglton = false });
}
public void Register<TFrom, TTo>(string token = "") where TTo : TFrom
{
string key =
typeof(TFrom).FullName +
(String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);
_instenceDic.Add(
key,
new InstenceModel { ObjectType = typeof(TTo), IsSinglton = false });
}
// 单例状态
public void RegisterSingle<T>()
{
_instenceDic.Add(
typeof(T).FullName!,
new InstenceModel { ObjectType = typeof(T), IsSinglton = true });
}
public void RegisterSingle<TFrom, TTo>(string token = "") where TTo : TFrom
{
string key =
typeof(TFrom).FullName +
(String.IsNullOrEmpty(token) ? "" : "_#%%$#_" + token);
_instenceDic.Add(
key,
new InstenceModel { ObjectType = typeof(TTo), IsSinglton = true });
}
public T Resolve<T>()
{
string key = typeof(T).FullName;
if (_instenceDic.ContainsKey(key))
{
if (_instenceDic[key].IsSinglton)
{
if (_instenceDic[key].Instence is null)
{
lock (_instanceLock)
{
if (_instenceDic[key].Instence is null)
{
// 在单例模式下,之前没有创建实例的前提下调用
return (T)CreateInstence(key, typeof(T));
}
return (T)_instenceDic[key].Instence;
}
}
return (T)_instenceDic[key].Instence;
}
else
{
// 在瞬时模式下,每次都调用
return (T)CreateInstence(key, typeof(T));
}
}
return default(T);
}
private object CreateInstence(string key, Type type)
{
#region 检查构造函数的参数
// 如果有参数,根据类型动态创建实例
ConstructorInfo[] cis = _instenceDic[key].ObjectType.GetConstructors();
ParameterInfo[] cpis = cis[0].GetParameters();
// 参数列表
List<object> objects = new List<object>();
foreach (ParameterInfo cpi in cpis)
{
// AAA MySqlDA.
string paramTypeKey = cpi.ParameterType.FullName;
if (cpi.IsDefined(typeof(DependyAttribute), false))
{
var attr = cpi.GetCustomAttribute<DependyAttribute>();
paramTypeKey += string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token;
}
if (_instenceDic.ContainsKey(paramTypeKey))
{
if (_instenceDic[paramTypeKey].IsSinglton)
{
if (_instenceDic[paramTypeKey].Instence is null)
{
//_instenceDic[paramTypeKey].Instence =
// Activator.CreateInstance(_instenceDic[paramTypeKey].ObjectType);
_instenceDic[paramTypeKey].Instence =
CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
}
}
else
{
_instenceDic[paramTypeKey].Instence =
CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
}
objects.Add(_instenceDic[paramTypeKey].Instence);
}
else
objects.Add(null);
}
#endregion 检查构造函数的参数
// 创建对象实例,创建之前需要准备好这个对象的构造函数的参数
var obj = Activator.CreateInstance(_instenceDic[key].ObjectType, objects.ToArray());
_instenceDic[key].Instence = obj;
#region 检查属性的注入
//
// 哪些属性需要注入 可以通过特性进行区分
PropertyInfo[] pis = type.GetProperties();
//type.GetFields();// 获取所有字段
foreach (var pi in pis)
{
// 判断属性上是否有特定标记,如果有,实例化这个属性
if (pi.IsDefined(typeof(DependyAttribute), false))
{
var attr = pi.GetCustomAttribute<DependyAttribute>();
// 属性注入的时候
string paramTypeKey = pi.PropertyType.FullName +
(string.IsNullOrEmpty(attr.Token) ? "" : "_#%%$#_" + attr.Token);
if (_instenceDic.ContainsKey(paramTypeKey))
{
if (_instenceDic[paramTypeKey].IsSinglton)
{
if (_instenceDic[paramTypeKey].Instence is null)
{
_instenceDic[paramTypeKey].Instence =
CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
}
}
else
{
_instenceDic[paramTypeKey].Instence =
CreateInstence(paramTypeKey, _instenceDic[paramTypeKey].ObjectType);
}
// 如果已经创建了实例,设置给当前对象的对应属性
// 第一个参数,指这个值要设置给哪个对象实例的这个属性
pi.SetValue(obj, _instenceDic[paramTypeKey].Instence);
}
}
}
#endregion 检查属性的注入
return obj;
}
// 1、对象中的参数未注入
// 2、多个实现的使用
// 3、属性注入
// 4、瞬时注入/单例模式
}
internal class InstenceModel
{
public object Instence { get; set; }
public bool IsSinglton { get; set; }
public Type ObjectType { get; set; }
}
}
总结
通过 MyIoc
这个自定义IoC容器,我们可以看到IoC容器的核心功能:
- 对象生命周期管理:支持瞬态模式和单例模式。
- 依赖注入:支持构造函数注入和属性注入。
- 灵活性:支持单接口多实现的注入。
虽然 MyIoc
是一个简单的实现,但它清晰地展示了IoC容器的核心思想和实现方式。在实际项目中,可以使用更成熟的IoC容器(如Autofac、Unity等)来获得更强大的功能和更好的性能。