您的位置:首页 > 编程语言 > C#

c#实现简单的注入容器,认识注入容器的基本原理

2017-09-21 16:41 134 查看
在学习了反射和注入的概念后,加上项目中也用到 比如 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)

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,注册实现接口和实现类的映射关系,获取实体则生成注入后的类型。

构造注入这里如果没有用特性进行标识,则默认取参数最多的一个进行构造。

源码已传到  码云
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: