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