现在的编程思想,离不开IOC依赖注入,手写实现一个简易IOC容器,更深入理解依赖注入
还没了解IOC的可以查阅.net IOC框架 Unity&Autofac
本文章主要实现
- IOC容器基础注册
- 进阶完善别名以及构造函数注入
- 对象的生命周期管理
一、IoC容器实现
测试接口类
public interface ILanguage
{
public string GetContent();
}
测试接口实现类
public class Chinese : ILanguage
{
public string GetContent()
{
return "学习中文";
}
}
public class English : ILanguage
{
public string GetContent()
{
return "Learning English";
}
}
自定义容器接口类
public interface IMyContainer
{
/// <summary>
/// 注册单一类型
/// </summary>
/// <typeparam name="TType"></typeparam>
void RegisterType<TType>();
/// <summary>
/// 注册单一类型
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="name">别名</param>
void RegisterType<TType>(string name);
/// <summary>
/// 映射关系
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <typeparam name="TImplementation"></typeparam>
void RegisterType<TType, TImplementation>();
/// <summary>
/// 映射关系
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <typeparam name="TImplementation"></typeparam>
/// <param name="name">别名</param>
void RegisterType<TType, TImplementation>(string name);
/// <summary>
/// 解析类型
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <returns></returns>
TType Resolve<TType>();
/// <summary>
/// 解析类型
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="name">别名</param>
/// <returns></returns>
TType Resolve<TType>(string name);
容器接口实现类
public class MyContainer : IMyContainer
{
//键用来映射关系,使用字典作为登记本
private static readonly Dictionary<string, object> ContainerDictionary = new Dictionary<string, object>();
public void RegisterType<TType>()
=> RegisterType<TType, TType>(null);
public void RegisterType<TType, TImplementation>()
=> RegisterType<TType, TImplementation>(null);
public void RegisterType<TType>(string name)=>
RegisterType<TType, TType>(null);
public void RegisterType<TType, TImplementation>(string name)
{
string key = typeof(TType).FullName;
if (!string.IsNullOrEmpty(name)) key = name;
if (ContainerDictionary.ContainsKey(key))
ContainerDictionary[key] = typeof(TImplementation); //如果存在采取覆盖形式
else
ContainerDictionary.Add(key, typeof(TImplementation));//将传进来的泛型Type进行关系映射
}
public TType Resolve<TType>() =>
Resolve<TType>(null);
public TType Resolve<TType>(string name)
{
//解析泛型Type获取key
var key = typeof(TType).FullName;
if (!string.IsNullOrEmpty(name)) key = name;
// 根据key从容器中获取实现类
var type = (Type)ContainerDictionary[key];
//创建对象
return (TType)Activator.CreateInstance(type);
}
}
main函数依赖注入测试
static void Main(string[] args)
{
var container = new MyContainer();
container.RegisterType<ILanguage, Chinese>();
//使用别名注册
container.RegisterType<ILanguage, English>("english");
var language = container.Resolve<ILanguage>();
var english = container.Resolve<ILanguage>("english");
Console.WriteLine(language.GetContent());
Console.WriteLine(english.GetContent());
Console.Read();
}
输出结果
image.png
二、构造函数注入
创建特性类标记构造函数
public class MyinjectionAttribute : Attribute
{
}
使用自定义创建实例类进行对象实例化
1.优先使用被特性标记的构造函数
2.没有特性标记选择参数最多的构造函数,参数个数一致,按默认顺序选择第一个
//多个构造函数选择构造函数来创建实例
//1.优先使用被特性标记的构造函数
//2.没有特性标记选择参数最多的构造函数,参数个数一致,按默认顺序选择第一个
/// <summary>
/// 创建实例
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private object CreateInstance(Type type)
{
//获取所有的构造函数
var ctors = type.GetConstructors();
//获取被标记的构造函数
var ctor = ctors.FirstOrDefault(t => t.IsDefined(typeof(MyinjectionAttribute), true));
if (ctor != null) CreateInstance(type, ctor);
//没有特性获取参数最多的一个
ctor = ctors.OrderByDescending(t => t.GetParameters().Length).First();
return CreateInstance(type, ctor);
}
/// <summary>
/// 构造函数注入
/// </summary>
/// <param name="type"></param>
/// <param name="ctor"></param>
/// <returns></returns>
private object CreateInstance(Type type, ConstructorInfo ctor)
{
//获取构造函数参数
var paraArray = ctor.GetParameters();
if (paraArray.Length == 0)
{
return Activator.CreateInstance(type);
}
var parameters = new List<object>();
foreach (var para in paraArray)
{
//通过反射获取参数类型名
var paraKey = para.ParameterType.FullName;
//根据paraKey从字典获取已注册的实现类
var paraType = (Type)ContainerDictionary[paraKey];
// 递归注入构造参数
var paraObj = CreateInstance(paraType);
//将对象存储在list数组
parameters.Add(paraObj);
}
return Activator.CreateInstance(type, parameters.ToArray());
}
修改Resolve函数调用自身创建对象函数CreateInstance
public TType Resolve<TType>(string name)
{
//解析泛型Type获取key
var key = typeof(TType).FullName;
if (!string.IsNullOrEmpty(name)) key = name;
// 根据key从容器中获取实现类
var type = (Type)ContainerDictionary[key];
//创建对象
return (TType)CreateInstance(type);
}
新建Learn类进行测试
public class Learn
{
private ILanguage Language { get; set; }
//标记特性
[Myinjection]
public Learn(ILanguage language)
{
Language = language;
}
public void Read()
{
Console.WriteLine(Language.GetContent());
}
}
main函数
static void Main(string[] args)
{
var container = new MyContainer();
container.RegisterType<ILanguage, Chinese>();
//注入learn
container.RegisterType<Learn>();
var learn = container.Resolve<Learn>();
learn.Read();
Console.Read();
}
测试结果:
image.png
三、生命周期管理
这里实现三种常用生命周期模式:单例,瞬时,线程单例(作用域)
定义生命周期管理接口类,便于扩展
public interface ILifeTimeManager
{
object CreateInstance(Type type, params object[] args);
}
单例模式实现类
public class SingletonLifeTimeManager : ILifeTimeManager
{
//单例字典
private readonly Dictionary<string, object> _singletonDictionary = new Dictionary<string, object>();
public object CreateInstance(Type type, params object[] args)
{
var key = type.FullName;
if (_singletonDictionary.ContainsKey(key)) return _singletonDictionary[key];
var instance = Activator.CreateInstance(type, args);
_singletonDictionary.Add(key, instance);
return instance;
}
}
瞬时模式实现类
public class TransientLifeTimeManger : ILifeTimeManager
{
public object CreateInstance(Type type, params object[] args)
{
return Activator.CreateInstance(type, args);
}
}
线程单例实现类
public class PerThreadLifeTimeManager : ILifeTimeManager
{
//通过线程本地存储进行线程单例管理
private readonly ThreadLocal<Dictionary<string, object>> _perThreadDictonary =
new ThreadLocal<Dictionary<string, object>>();
public object CreateInstance(Type type, params object[] args)
{
//判断线程存储是否存在字段对象
if (_perThreadDictonary.Value == null)
_perThreadDictonary.Value = new Dictionary<string, object>();
var key = type.FullName;
if (_perThreadDictonary.Value.ContainsKey(key)) return _perThreadDictonary.Value[key];
var instance = Activator.CreateInstance(type, args);
_perThreadDictonary.Value.Add(key, instance);
return instance;
}
}
定义生命周期类型静态类(用于管理生命周期类型)
public static class TypeLifeTime
{
public static ILifeTimeManager Singleton = new SingletonLifeTimeManager();
public static ILifeTimeManager Transient = new TransientLifeTimeManger();
public static ILifeTimeManager PerThread = new PerThreadLifeTimeManager();
}
定义保存注册映射信息实体类,以及扩展方法类
public class RegisteredType
{
public Type TargetType { get; set; }
public ILifeTimeManager LifeTimeManager { get; set; }
}
public static class RegisteredTypeExtension
{
public static object CreateInstance(this RegisteredType type, params object[] args)
{
//使用生命周期管理创建实例
return type.LifeTimeManager.CreateInstance(type.TargetType, args);
}
}
IMyContainer 接口类新增生命周期管理接口
/// <summary>
/// 注册单一类型
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="lifeTimeManager">生命周期管理</param>
void RegisterType<TType>(ILifeTimeManager lifeTimeManager);
/// <summary>
/// 注册单一类型
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <param name="name">别名</param>
/// <param name="lifeTimeManager">生命周期管理</param>
void RegisterType<TType>(string name, ILifeTimeManager lifeTimeManager);
/// <summary>
/// 映射关系
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <typeparam name="TImplementation"></typeparam>
/// <param name="lifeTimeManager">生命周期管理</param>
void RegisterType<TType, TImplementation>(ILifeTimeManager lifeTimeManager);
/// <summary>
/// 映射关系
/// </summary>
/// <typeparam name="TType"></typeparam>
/// <typeparam name="TImplementation"></typeparam>
/// <param name="name">别名</param>
/// <param name="lifeTimeManager">生命周期管理</param>
void RegisterType<TType, TImplementation>(string name, ILifeTimeManager lifeTimeManager);
MyContainer 接口实现类修改如下
public class MyContainer : IMyContainer
{
//键用来映射关系,使用字典作为登记本
private static readonly Dictionary<string, RegisteredType> ContainerDictionary = new Dictionary<string, RegisteredType>();
public void RegisterType<TType>()
=> RegisterType<TType, TType>("");
public void RegisterType<TType, TImplementation>()
=> RegisterType<TType, TImplementation>("");
public void RegisterType<TType>(string name) =>
RegisterType<TType, TType>("");
public void RegisterType<TType, TImplementation>(string name)=>
RegisterType<TType, TImplementation>(name, TypeLifeTime.Transient);
public void RegisterType<TType>(ILifeTimeManager lifeTimeManager)=>
RegisterType<TType, TType>(lifeTimeManager);
public void RegisterType<TType, TImplementation>(ILifeTimeManager lifeTimeManager)=>
RegisterType<TType, TImplementation>("", lifeTimeManager);
public void RegisterType<TType>(string name, ILifeTimeManager lifeTimeManager) =>
RegisterType<TType, TType>(name, lifeTimeManager);
public void RegisterType<TType, TImplementation>(string name, ILifeTimeManager lifeTimeManager)
{
string key = typeof(TType).FullName;
if (!string.IsNullOrEmpty(name)) key = name;
if (ContainerDictionary.ContainsKey(key)) //如果存在覆盖
ContainerDictionary[key] = new RegisteredType
{
TargetType = typeof(TImplementation),
LifeTimeManager = lifeTimeManager
};
else
ContainerDictionary.Add(key, new RegisteredType
{
TargetType = typeof(TImplementation),
LifeTimeManager = lifeTimeManager
});//将传进来的泛型Type进行关系映射
}
public TType Resolve<TType>() =>
Resolve<TType>("");
public TType Resolve<TType>(string name)
{
//解析泛型Type获取key
var key = typeof(TType).FullName;
if (!string.IsNullOrEmpty(name)) key = name;
// 根据key从容器中获取实现类
var type = ContainerDictionary[key];
//创建对象
return (TType)CreateInstance(type);
}
//多个构造函数选择构造函数来创建实例
//1.优先使用被特性标记的构造函数
//2.没有特性标记选择参数最多的构造函数,参数个数一致,按默认顺序选择第一个
/// <summary>
/// 创建实例
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
private object CreateInstance(RegisteredType type)
{
//获取所有的构造函数
var ctors = type.TargetType.GetConstructors();
//获取被标记的构造函数
var ctor = ctors.FirstOrDefault(t => t.IsDefined(typeof(MyinjectionAttribute), true));
if (ctor != null) CreateInstance(type, ctor);
//没有特性获取参数最多的一个
ctor = ctors.OrderByDescending(t => t.GetParameters().Length).First();
return CreateInstance(type, ctor);
}
/// <summary>
/// 构造函数注入
/// </summary>
/// <param name="type"></param>
/// <param name="ctor"></param>
/// <returns></returns>
private object CreateInstance(RegisteredType type, ConstructorInfo ctor)
{
//获取构造函数参数
var paraArray = ctor.GetParameters();
if (paraArray.Length == 0)
{
return type.CreateInstance();
}
var parameters = new List<object>();
foreach (var para in paraArray)
{
//通过反射获取参数类型名
var paraKey = para.ParameterType.FullName;
//根据paraKey从字典获取已注册的实现类
var paraType = ContainerDictionary[paraKey];
// 递归注入构造参数
var paraObj = CreateInstance(paraType);
//将对象存储在list数组
parameters.Add(paraObj);
}
//调用生命周期管理器创建时间方法
//type.LifeTimeManager.CreateInstance(type, parameters.ToArray());
//这里使用扩展类调用生命周期管理器创建时间方法
return type.CreateInstance(parameters.ToArray());
}
}
接下来测试一下
main函数
static void Main(string[] args)
{
var container = new MyContainer();
//依赖注入 瞬时默认
container.RegisterType<ILanguage, Chinese>();
var language1 = container.Resolve<ILanguage>();
var language2 = container.Resolve<ILanguage>();
Console.WriteLine($"-----------------------瞬时默认-------------------------");
Console.WriteLine($"language1 与 language2:{ReferenceEquals(language1, language2)}\r\n");
//线程单例
Console.WriteLine($"-----------------------线程单例-------------------------");
container.RegisterType<ILanguage, Chinese>(TypeLifeTime.PerThread);
ILanguage tlanguage1 = null;
var task1 = Task.Run(() => {
tlanguage1 = container.Resolve<ILanguage>();
Console.WriteLine($"tlanguage1 线程id:{Thread.CurrentThread.ManagedThreadId}");
});
ILanguage tlanguage2 = null;
ILanguage tlanguage3 = null;
var task2 = Task.Run(() => {
tlanguage2 = container.Resolve<ILanguage>();
tlanguage3 = container.Resolve<ILanguage>();
Console.WriteLine($"tlanguage2 线程id:{Thread.CurrentThread.ManagedThreadId}");
Console.WriteLine($"tlanguage3 线程id:{Thread.CurrentThread.ManagedThreadId}");
});
task1.Wait();
task2.Wait();
Console.WriteLine($"tlanguage1 与 tlanguage2 :{ReferenceEquals(tlanguage1, tlanguage2)}");
Console.WriteLine($"tlanguage2 与 tlanguage3 :{ReferenceEquals(tlanguage2, tlanguage3)}\r\n");
//单例模式
container.RegisterType<ILanguage, Chinese>(TypeLifeTime.Singleton);
var slanguage1 = container.Resolve<ILanguage>();
var slanguage2 = container.Resolve<ILanguage>();
Console.WriteLine($"-----------------------单例模式-------------------------");
Console.WriteLine($"slanguage1 与 slanguage2:{ReferenceEquals(slanguage1, slanguage2)}");
Console.Read();
}
输出结果:
image.png
附上项目结构图:
image.png
文章就到这里了,还有很多功能未实现(如函数注入,属性注入等),主要为了了解学习IOC容器- -
项目源码:https://github.com/booker1/IOC