c#实现简单的注入容器,认识注入容器的基本原理
2017-09-21 16:41
134 查看
在学习了反射和注入的概念后,加上项目中也用到 比如 AutoFuc 还有 unity 等容器。就有点想写自己的容器的想法。
然后 搜索了下 注入容器相关的文章,大多是多某个成熟的注入容器的代码进行解析,或者是对 注入概念的解析。成熟的框架考虑到方方面面,源码对于新手来说可能不是很好接收(虽然自己也并不是什么大神),而概念上 哪怕看的多也有可能不知道从何下手。
注入其实主要就靠反射创建对象,只是在创建的时候根据需求给构造函数赋值或者给某个属性或者字段赋值。
然后按照自己的理解,写了一个简单的容器,使用的是 c#语言,自己写的这个容器经过在 asp.net mvc 做了注入的测试。
代码比较简单,下面上代码:
提供几个特性(Attribute),用于标识哪个构造或者属性字段需要注入:
然后是核心代码:
代码比较简单,相对就好理解一些。字典用来保存注册了的类型。对外提供主要两个方法,注册 Register 和 获取实体Get Instance,注册实现接口和实现类的映射关系,获取实体则生成注入后的类型。
构造注入这里如果没有用特性进行标识,则默认取参数最多的一个进行构造。
源码已传到 码云
然后 搜索了下 注入容器相关的文章,大多是多某个成熟的注入容器的代码进行解析,或者是对 注入概念的解析。成熟的框架考虑到方方面面,源码对于新手来说可能不是很好接收(虽然自己也并不是什么大神),而概念上 哪怕看的多也有可能不知道从何下手。
注入其实主要就靠反射创建对象,只是在创建的时候根据需求给构造函数赋值或者给某个属性或者字段赋值。
然后按照自己的理解,写了一个简单的容器,使用的是 c#语言,自己写的这个容器经过在 asp.net mvc 做了注入的测试。
代码比较简单,下面上代码:
提供几个特性(Attribute),用于标识哪个构造或者属性字段需要注入:
namespace InjectContainer { [AttributeUsage(AttributeTargets.Constructor)] public class ConstructorInjectAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property)] public class PropertyInjectAttribute : Attribute { } [AttributeUsage(AttributeTargets.Field)] public class FieldInjectAttribute : Attribute { } }
然后是核心代码:
namespace InjectContainer { public class Container { private static Dictionary<string, Type> dicToInstances = null; private static Dictionary<string, List<Type>> dicReturnTypeInfo = null; private static object objLock = null; private static Container container = null; static Container() { container = new Container(); dicToInstances = new Dictionary<string, Type>(); dicReturnTypeInfo = new Dictionary<string, List<Type>>(); objLock = new object(); } public Container GetContainer() { return container; } #region 重载注册器 /// <summary> /// 接口注册 /// </summary> /// <param name="toNameSpace">目标程序集命名空间</param> public void Register(string toNameSpace) 4000 { var toAssembly = Assembly.Load(toNameSpace); var types = toAssembly.GetTypes(); Register(types); } /// <summary> /// 接口注册 /// </summary> /// <param name="types">类型数组</param> public void Register(params Type[] types) { foreach (var type in types) { var interfaces = type.GetInterfaces(); foreach (var inter in interfaces) { if (dicToInstances.ContainsKey(inter.FullName)) continue; dicToInstances.Add(inter.FullName, type); } } } /// <summary> /// 接口注册 /// </summary> /// <typeparam name="TFrom">来源类型</typeparam> /// <typeparam name="TTo">目标类型</typeparam> public void Register<TFrom, TTo>() { Register(typeof(TFrom), typeof(TTo)); } /// <summary> /// 接口注册 /// </summary> /// <param name="fromType">来源类型</param> /// <param name="toType">目标类型</param> public void Register(Type fromType, Type toType) { dicToInstances.Add(fromType.FullName, toType); } #endregion /// <summary> /// 获取实体 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public T GetInstance<T>() { return GetInstance<T>(typeof(T)); } /// <summary> /// 获取实体 /// </summary> /// <param name="type"></param> /// <returns></returns> public T GetInstance<T>(Type type) { if (type.IsInterface) { if (dicToInstances.ContainsKey(type.FullName)) return GetInstance<T>(dicToInstances[type.FullName]); else return default(T); } else { return CreateInstance<T>(type); } } private T CreateInstance<T>(Type type) { List<Type> typesOfParameter = new List<Type>(); if (dicReturnTypeInfo.ContainsKey(type.FullName)) { //如果有类型数据就不需要再获取一次了 typesOfParameter = dicReturnTypeInfo[type.FullName]; } else { lock (objLock) { if (!dicReturnTypeInfo.ContainsKey(type.FullName)) { //构造函数注入 ConstructorInfo constructor = null; var ConstructorsInfo = type.GetConstructors(); if (ConstructorsInfo.Count() > 0) { var dicCountParameters = new Dictionary<int, ParameterInfo[]>(); foreach (var Constructor in ConstructorsInfo) { var tempParameters = Constructor.GetParameters(); dicCountParameters.Add(tempParameters.Count(), tempParameters); if (Constructor.GetCustomAttribute(typeof(ConstructorInjectAttribute)) != null) { constructor = Constructor; break; } } //如果没有指定特性,则默认取参数最多的一个 var parameters = constructor==null? dicCountParameters.OrderByDescending(c=>c.Key).FirstOrDefault().Value : constructor.GetParameters(); foreach (var item in parameters) { Type fromType = item.ParameterType; typesOfParameter.Add(fromType); } dicReturnTypeInfo.Add(type.FullName, typesOfParameter); } } } } List<object> param = new List<object>(); foreach (var pType in typesOfParameter) { if (dicToInstances.ContainsKey(pType.FullName)) param.Add(GetInstance<object>(dicToInstances[pType.FullName])); else throw new Exception($"指定类型未注册:{pType.FullName}"); } T t = default(T); if (param.Count > 0) t = (T)Activator.CreateInstance(type, param.ToArray()); else t = (T)Activator.CreateInstance(type); //属性注入 var properties = type.GetProperties(); foreach (var property in properties) { var attribute = property.GetCustomAttribute(typeof(PropertyInjectAttribute)); if (attribute != null) property.SetValue(t, GetInstance<object>(property.PropertyType)); } //字段注入 var filds = type.GetFields(); foreach (var fild in filds) { var attribute = fild.GetCustomAttribute(typeof(FieldInjectAttribute)); if (attribute != null) fild.SetValue(t, GetInstance<object>(fild.FieldType)); } return t; } } }
代码比较简单,相对就好理解一些。字典用来保存注册了的类型。对外提供主要两个方法,注册 Register 和 获取实体Get Instance,注册实现接口和实现类的映射关系,获取实体则生成注入后的类型。
构造注入这里如果没有用特性进行标识,则默认取参数最多的一个进行构造。
源码已传到 码云
相关文章推荐
- ADO.NET .net core2.0添加json文件并转化成类注入控制器使用 简单了解 iTextSharp实现HTML to PDF ASP.NET MVC 中 Autofac依赖注入DI 控制反转IOC 了解一下 C# AutoMapper 了解一下
- C# 实现简单打印(三)-认识打印控件,创建一个带打印功能的程序
- 实现简单的构造函数注入容器
- 从零开始写C# MVC框架之--- 用autofac ioc 容器实现依赖注入
- 基于c#实现的九九乘法表(简单实例)
- C# 实现IP视频监控(摄像头)画面推送(简单的不能再简单的DEMO)
- 根据权重随机选取指定条数记录的简单算法实现(C#)【含源代码】
- 用C#实现简单的打字闯关游戏
- 运用Unity实现依赖注入[结合简单三层实例]
- C# WinForm国际化实现的简单方法
- c#简单实现二维数组和二维数组列表List<>的转置
- bash实现一个简单的错误(mutation)注入工具
- C#实现简单的汽车租赁系统
- 用C#实现实现简单的 Ping 的功能,用于测试网络是否已经联通
- C#钩子实现简单鼠标键盘的监控和屏蔽
- 使用c#实现简单的数据库添加和查询
- 记住密码超简单实现(C#)
- C#实现的封装CURD到SqlHelper类用法简单分析
- Tomcat源码之旅--最简单的Servlet容器实现
- 使用socket实现简单的客户端和服务端通信(C#语言)