c#实现简单的注入容器,认识注入容器的基本原理
来源:互联网 发布:csgo和cf知乎 编辑:程序博客网 时间:2024/05/19 23:15
在学习了反射和注入的概念后,加上项目中也用到 比如 AutoFuc 还有 unity 等容器。就有点想写自己的容器的想法。
然后 搜索了下 注入容器相关的文章,大多是多某个成熟的注入容器的代码进行解析,或者是对 注入概念的解析。成熟的框架考虑到方方面面,源码对于新手来说可能不是很好接收(虽然自己也并不是什么大神),而概念上 哪怕看的多也有可能不知道从何下手。
注入其实主要就靠反射创建对象,只是在创建的时候根据需求给构造函数赋值或者给某个属性或者字段赋值。
然后按照自己的理解,写了一个简单的容器,使用的是 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) { 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,注册实现接口和实现类的映射关系,获取实体则生成注入后的类型。
构造注入这里如果没有用特性进行标识,则默认取参数最多的一个进行构造。
源码已传到 码云
阅读全文
0 0
- c#实现简单的注入容器,认识注入容器的基本原理
- IOC容器的依赖注入
- spring ioc容器的注入
- IOC容器的依赖注入
- 自建简单的依赖注入容器Ioc Container
- easyjweb容器的三种注入方式
- 依赖注入容器Unity的基础知识
- web 容器拿到spring 注入的对象
- 依赖注入容器Autofac的详解
- 微软的依赖注入容器,Unity
- spring容器(注入的方式)
- Spring的IOC容器—依赖注入
- YII框架的依赖注入容器
- 基于Spring容器Bean的动态注入
- IOC容器的基本原理
- Ioc容器-Autofac 之四-依赖注入框架Autofac的简单使用
- 【Spring源码--IOC容器的实现】(六)Bean的依赖注入
- java容器的认识
- 简单的Servlet容器_根据请求决定具体servlet
- 互联网精彩好文
- Sprintf函数相关用法
- 给mysql的root %用户添加grant权限。并给创建的用户赋予权限
- 经典SQL练习题
- c#实现简单的注入容器,认识注入容器的基本原理
- (CodeForces
- 学生程序设计链接
- 阴影的变化
- JAVA Scanner 用法注意事项(scanner 使用错误:Exception in thread "main" java.util.NoSuchElementExceptionation )
- SpringMVC 学习笔记(七) JSON返回:HttpMessageConverter作用
- Oracle表空间-还原表空间新建
- poj3680(费用流)
- macos python3借用pip安装第三方包