Castle是.NET平台上的一个开源项目,为企业级开发和WEB应用程序开发提供完整的服务。Windsor是Castle下的一个项目,用于提供IOC的解决方案。IOC被称为控制反转或者依赖注入(Inversion of Control)
以下介绍如何通过Castle.Windsor实现对类的成员属性或字段进行自动注入:
一、自动注入核心代码:
using Castle.Core;
using Castle.Core.Resource;
using Castle.MicroKernel;
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using System;
using System.Collections.Generic;
using System.Reflection;
// 成员注解自动注入属性类,可注解字段和属性
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Property)]
public class InstanceAttribute : Attribute
{
// 获取或设置需要注入对象的ID值
public string ID
{
get;
set;
}
// 获取或设置需要注入对象的类型
public Type Type
{
get;
set;
}
}
// 成员注解自动注入功能类,继承Castle.Windsor的WindsorContainer
public class InstanceProvider : WindsorContainer
{
// 定义Castle.Windsor在程序配置文件中的节点
private static readonly string ConfigRoot = "windsor";
// 定义类的成员注解信息字典
private static Dictionary<Type, Dictionary<MemberInfo, InstanceAttribute>> _InstanceMembers = new Dictionary<Type, Dictionary<MemberInfo, InstanceAttribute>>();
// 构造函数初始化程序默认配置文件的Castle.Windsor配置信息(也可以指定其他配置文件)
public InstanceProvider()
: base(new XmlInterpreter(new ConfigResource(InstanceProvider.ConfigRoot)))
{
// 绑定IoC组件创建事件
this.Kernel.ComponentCreated += this.Kernel_ComponentCreated;
}
// 获取类型的成员注解信息
private Dictionary<MemberInfo, InstanceAttribute> GetInstanceMembers(Type type)
{
// 定义类型的成员注解信息
Dictionary<MemberInfo, InstanceAttribute> instanceMembers;
// 获取Castle.Windsor的IoC接口
IKernel kernel = this.Kernel;
// 线程安全锁,防止多线程对成员注解信息字典操作的冲突
lock (InstanceProvider._InstanceMembers)
{
// 判断当前类型是否已存在成员注解信息
if (InstanceProvider._InstanceMembers.ContainsKey(type))
{
// 根据类型获取所属的成员注解信息
instanceMembers = InstanceProvider._InstanceMembers[type];
}
else
{
// 新建成员注解信息
instanceMembers = new Dictionary<MemberInfo, InstanceAttribute>();
// 获取成员注解的属性类类型
Type instanceAttributeType = typeof(InstanceAttribute);
// 获取类型的成员信息
MemberInfo[] memberInfos = type.GetMembers();
foreach (MemberInfo memberInfo in memberInfos)
{
switch (memberInfo.MemberType)
{
case MemberTypes.Field:
// 获取字段成员
FieldInfo fieldInfo = memberInfo as FieldInfo;
// 获取成员注解对象
object[] fieldInstanceAttributes = memberInfo.GetCustomAttributes(instanceAttributeType, false);
// 查找有效的字段注解信息
foreach (InstanceAttribute instanceAttribute in fieldInstanceAttributes)
{
// 判断是否设置了需要注入对象的ID值
if (instanceAttribute.ID == null)
{
// 定义IoC组件类型
Type componentType;
// 判断是否设置了需要注入对象的类型
if (instanceAttribute.Type == null)
{
// 没有设置需要注入对象的类型则使用字段类型
componentType = fieldInfo.FieldType;
}
else
{
// 设置IoC组件类型
componentType = instanceAttribute.Type;
}
// 没有设置需要注入对象的ID值则根据组件类型判断是否存在对应的IoC组件
if (kernel.HasComponent(componentType))
{
// 添加成员注解信息项
instanceMembers.Add(memberInfo, instanceAttribute);
break;
}
}
else
{
// 根据注入对象的ID值判断是否存在Ioc组件
if (kernel.HasComponent(instanceAttribute.ID))
{
// 添加成员注解信息项
instanceMembers.Add(memberInfo, instanceAttribute);
break;
}
}
}
break;
case MemberTypes.Property:
// 获取属性成员
PropertyInfo propertyInfo = memberInfo as PropertyInfo;
// 判断属性成员是否可读写,并且Get、Set访问器的静态性是否一致
MethodInfo getMethodInfo = propertyInfo.GetGetMethodInfo();
MethodInfo setMethodInfo = propertyInfo.GetSetMethodInfo();
if (getMethodInfo != null && setMethodInfo != null && getMethodInfo.IsStatic == setMethodInfo.IsStatic)
{
// 获取属性注解对象
object[] propertyInstanceAttributes = memberInfo.GetCustomAttributes(instanceAttributeType, false);
// 查找有效的属性注解信息
foreach (InstanceAttribute instanceAttribute in propertyInstanceAttributes)
{
// 判断是否设置了需要注入对象的ID值
if (instanceAttribute.ID == null)
{
// 定义IoC组件类型
Type componentType;
// 判断是否设置了需要注入对象的类型
if (instanceAttribute.Type == null)
{
// 没有设置需要注入对象的类型则使用属性类型
componentType = propertyInfo.PropertyType;
}
else
{
// 设置IoC组件类型
componentType = instanceAttribute.Type;
}
// 没有设置需要注入对象的ID值则根据组件类型判断是否存在对应的IoC组件
if (kernel.HasComponent(componentType))
{
// 添加属性注解信息项
instanceMembers.Add(memberInfo, instanceAttribute);
break;
}
}
else
{
// 根据注入对象的ID值判断是否存在Ioc组件
if (kernel.HasComponent(instanceAttribute.ID))
{
// 添加属性注解信息项
instanceMembers.Add(memberInfo, instanceAttribute);
break;
}
}
}
}
break;
default:
break;
}
}
// 将获取到的成员注解信息保存到成员注解信息字典以备下次获取
InstanceProvider._InstanceMembers.Add(type, instanceMembers);
}
}
// 返回成员注解信息
return instanceMembers;
}
// 为对象进行属性注入,静态类可通过传入Type对象进行注入
public void Instance(object obj)
{
// 获取需要注入对象的类型
Type type;
// 判断对象是否是Type对象
if (obj is Type)
{
// 直接强制转换为Type对象
type = obj as Type;
}
else
{
// 获取对象的类型
type = obj.GetType();
}
// 获取对象的成员注入信息
Dictionary<MemberInfo, InstanceAttribute> instanceMembers = this.GetInstanceMembers(type);
// 获取Castle.Windsor的IoC接口
IKernel kernel = this.Kernel;
// 开始进行成员注入
foreach (KeyValuePair<MemberInfo, InstanceAttribute> item in instanceMembers)
{
switch (item.Key.MemberType)
{
case MemberTypes.Field:
// 获取字段注入信息
FieldInfo fieldInfo = item.Key as FieldInfo;
// 定义字段反射对象
object field;
// 根据字段是否是静态字段设置反射对象
if (fieldInfo.IsStatic)
{
field = null;
}
else
{
field = obj;
}
// 判断字段是否已经被赋值,只对未赋值字段进行注入
if (fieldInfo.GetValue(field) == null)
{
// 定义IoC组件类型
Type componentType;
// 判断是否设置了需要注入对象的类型
if (item.Value.Type == null)
{
// 没有设置需要注入对象的类型则使用字段类型
componentType = fieldInfo.FieldType;
}
else
{
// 设置IoC组件类型
componentType = item.Value.Type;
}
// 定义需要注入的字段值
object value;
// 判断是否设置了需要注入对象的ID值
if (item.Value.ID == null)
{
// 没有设置需要注入对象的ID值则根据类型获取对应的IoC组件
value = kernel.Resolve(componentType);
}
else
{
// 根据注入对象的ID值获取Ioc组件
value = kernel.Resolve(item.Value.ID, componentType);
}
// 通过反射为字段进行赋值
fieldInfo.SetValue(field, value);
}
break;
case MemberTypes.Property:
// 获取属性注入信息
PropertyInfo propertyInfo = item.Key as PropertyInfo;
// 定义属性反射对象
object property;
// 根据属性是否是静态属性设置反射对象
MethodInfo getMethodInfo = propertyInfo.GetGetMethod();
MethodInfo setMethodInfo = propertyInfo.GetSetMethod();
if (getMethodInfo.IsStatic && setMethodInfo.IsStatic)
{
property = null;
}
else
{
property = obj;
}
// 判断属性是否已经被赋值,只对未赋值属性进行注入
if (propertyInfo.GetValue(property, null) == null)
{
// 定义IoC组件类型
Type componentType;
// 判断是否设置了需要注入对象的类型
if (item.Value.Type == null)
{
// 没有设置需要注入对象的类型则使用属性类型
componentType = propertyInfo.PropertyType;
}
else
{
// 设置IoC组件类型
componentType = item.Value.Type;
}
// 定义需要注入的属性值
object value;
// 判断是否设置了需要注入对象的ID值
if (item.Value.ID == null)
{
// 没有设置需要注入对象的ID值则根据类型获取对应的IoC组件
value = kernel.Resolve(componentType);
}
else
{
// 根据注入对象的ID值获取Ioc组件
value = kernel.Resolve(item.Value.ID, componentType);
}
// 通过反射为属性进行赋值
propertyInfo.SetValue(property, value, null);
}
break;
default:
break;
}
}
}
// 订阅IoC组件创建事件
private void Kernel_ComponentCreated(ComponentModel model, object instance)
{
// 在每次创建IoC组件时进行成员注入
this.Instance(instance);
}
}
二、调用说明:
定义类,并对需要进行注入的属性或字段标记InstanceAttribute注解属性类。创建InstanceProvider对象,通过调用Instance方法将传入的类实例对象进行属性或字段的注入。如果是静态类可通过传入其Type对象进行注入。
更多信息请参阅:Windsor | Castle Project