IOC:有很多人把控制反转和依赖注入混为一谈,虽然在某种意义上来看他们是一体的,但好像又有些不同。
1. IOC(控制反转)是一个控制容器,DI(依赖注入)就是这个容器的运行机制。
2. IOC就是一种软件设计思想,DI是这种软件设计思想的一个实现。
关于Ioc的框架有很多,比如astle Windsor、Unity、Spring.NET、StructureMap,我们这边使用微软提供的Unity做示例,你可以使用 Nuget 添加 Unity ,
也可以引用Microsoft.Practices.Unity.dll和Microsoft.Practices.Unity.Configuration.dll。
a. 先介绍常规做法,代码比较简单,稍微看一下:
public interface IBaseRepository
{
void DoSomething();
}
public interface IRespository : IBaseRepository { }
public interface IUserRepository : IBaseRepository { }
public interface IShopRepository : IBaseRepository { }
public class Repository : IRespository
{
public void DoSomething()
{
Console.WriteLine("I am a Repository");
}
}
public class UserRepository : IUserRepository
{
public void DoSomething()
{
Console.WriteLine("I am a UserRepository");
}
}
public class ShopRepository : IShopRepository
{
public void DoSomething()
{
Console.WriteLine("I am a ShopRepository");
}
}
public interface ITestService
{
void DoSomething();
}
public class TestService : ITestService
{
private IRespository respository;
/// <summary>
/// 构造注入
/// </summary>
/// <param name="\_respository"></param>
public TestService(IRespository \_respository)
{
this.respository = \_respository;
}
/// <summary>
/// 属性注入
/// </summary>
\[Dependency\]
public IUserRepository UserRepository { get; set; }
public IShopRepository ShopRepository { get; set; }
/// <summary>
/// 方法注入
/// </summary>
/// <param name="\_shopRepository"></param>
\[InjectionMethod\]
public void SetShopRepository(IShopRepository \_shopRepository)
{
this.ShopRepository = \_shopRepository;
}
public void DoSomething()
{
respository.DoSomething();
UserRepository.DoSomething();
ShopRepository.DoSomething();
}
}
class Program
{
static void Main(string\[\] args)
{
UnityContainer container = new UnityContainer();
container.RegisterType<IRespository, Repository>();
container.RegisterType<IUserRepository, UserRepository>();
container.RegisterType<IShopRepository, ShopRepository>();
container.RegisterType<ITestService, TestService>();
TestService testService = container.Resolve<ITestService>() as TestService;
testService.DoSomething();
}
}
b. 还有一种是配置文件做法
这个是配置文件:
对应的代码也得改改:
InitializeComponent();
//创建容器
UnityContainer container = new UnityContainer();
UnityConfigurationSection configuration = ConfigurationManager.GetSection(UnityConfigurationSection.SectionName) as UnityConfigurationSection;
configuration.Configure(container, "defaultContainer");
//通过Resolve<ITestService>方法返回的是一个类型为TestService的对象,该对象的三个属性被进行了有效的初始化。
//这个简单的程序分别体现了接口注入(通过相应的接口根据配置解析出相应的实现类型)、构造器注入(属性IRespository)、属性注入(属性IUserRepository)和方法注入(属性IShopRepository)
TestService t = container.Resolve<ITestService>() as TestService ;
if (null != t)
{
t.DoSomething();
}
Unity有三种注入方式,构造,属性和方法注入,Unity注入也有自己的生命周期(默认瞬时生命周期:每次都是构造一个新的),下面就介绍下生命周期。
IUnityContainer container = new UnityContainer();
//默认瞬时生命周期,每次都是构造一个新的
container.RegisterType
//每线程生命周期管理器,就是保证每个线程返回同一实例
container.RegisterType
//容器控制生命周期管理,这个生命周期管理器是RegisterInstance默认使用的生命周期管理器,也就是单件实例,UnityContainer会维护一个对象实例的强引用,每次调用的时候都会返回同一对象
container.RegisterType
//分层生命周期管理器,这个管理器类似于ContainerControlledLifetimeManager,也是由UnityContainer来管理,也就是单件实例,针对某个层单例
//不过与ContainerControlledLifetimeManager不同的是,这个生命周期管理器是分层的,因为Unity的容器时可以嵌套的,所以这个生命周期管理器就是针对这种情况,当使用了这种生命周期管理器,父容器和子容器所维护的对象的生命周期是由各自的容器来管理
container.RegisterType
//这个生命周期是为了解决循环引用而重复引用的生命周期
container.RegisterType
//外部控制生命周期管理器,这个生命周期管理允许你使用RegisterType和RegisterInstance来注册对象之间的关系,但是其只会对对象保留一个弱引用,其生命周期交由外部控制,也就是意味着你可以将这个对象缓存或者销毁而不用在意UnityContainer,而当其他地方没有强引用这个对象时,其会被GC给销毁掉。
//在默认情况下,使用这个生命周期管理器,每次调用Resolve都会返回同一对象(单件实例),如果被GC回收后再次调用Resolve方法将会重新创建新的对象
container.RegisterType
怎么自己实现一个简单的IOC容器呢?本次只实现一个简单的版本,生命周期只实现了三种,分别是瞬时,单例和线程单例。
a.首先定义一个生命周期的枚举 :
public enum LifeTimeType
{
///
Transient,
/// <summary>
/// 单例
/// </summary>
Singleton,
/// <summary>
/// 线程单例
/// </summary>
PerThread
}
b. 定义一个保存注册映射信息的对象:
public class RegisterInfo
{
///
public Type TargetType { get; set; }
///
public LifeTimeType LifeTime { get; set; }
}
c. 定义三个Attribute,直接写一起了:
[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
public class DependencyAttribute : Attribute
{
public LifeTimeType _lifeTimeType { get; set; }
public DependencyAttribute(LifeTimeType lifeTimeType = LifeTimeType.Transient)
{
this.\_lifeTimeType = lifeTimeType;
}
}
[AttributeUsage(AttributeTargets.Constructor)]
public class InjectionConstructorAttribute : Attribute
{
public InjectionConstructorAttribute()
{ }
}
\[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)\]
public class InjectionMethodAttribute : Attribute
{
private LifeTimeType \_lifeTimeType { get; set; }
public InjectionMethodAttribute(LifeTimeType lifeTimeType = LifeTimeType.Transient)
{
this.\_lifeTimeType = lifeTimeType;
}
}
d. 定义一个容器的接口:
public interface IIOCContainer
{
void RegisterType<TFrom, TTo>(LifeTimeType lifeTimeType = LifeTimeType.Transient);
T Resolve<T>();
}
e. 实现该接口的方法,这是整个容器的关键代码,代码比较长,写的可能有错误,欢迎指正:
public class IOCContainer : IIOCContainer
{
///
private Dictionary
/// <summary>
/// 缓存起来,类型的对象实例
/// </summary>
private Dictionary<Type, object> TypeObjectDictionary = new Dictionary<Type, object>();
public void RegisterType<TFrom, TTo>(LifeTimeType lifeTimeType = LifeTimeType.Transient)
{
ContainerDictionary.Add(typeof(TFrom).FullName, new RegisterInfo()
{
TargetType = typeof(TTo),
LifeTime = lifeTimeType
});
}
public T Resolve<T>()
{
RegisterInfo info = ContainerDictionary\[typeof(T).FullName\];
Type type = ContainerDictionary\[typeof(T).FullName\].TargetType;
T result = default(T);
result = (T)CreateTypeByRegisterType(info, type);
return result;
}
private object CreateObject(Type type)
{
ConstructorInfo\[\] ctorArray = type.GetConstructors();
ConstructorInfo ctor = null;
if (ctorArray.Count(c => c.IsDefined(typeof(InjectionConstructorAttribute), true)) > )
{
ctor = ctorArray.FirstOrDefault(c => c.IsDefined(typeof(InjectionConstructorAttribute), true));
}
else
{
ctor = ctorArray.OrderByDescending(c => c.GetParameters().Length).FirstOrDefault();
}
List<object> paraList = new List<object>();
foreach (var parameter in ctor.GetParameters())
{
Type paraType = parameter.ParameterType;
RegisterInfo info = ContainerDictionary\[paraType.FullName\];
Type targetType = info.TargetType;
object para = null;
para = CreateTypeByRegisterType(info, targetType);
//递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数
paraList.Add(para);
}
object objType = Activator.CreateInstance(type, paraList.ToArray());
//属性注入
var properties = type.GetProperties()
.Where(p => p.IsDefined(typeof(DependencyAttribute), false)).ToList();
foreach (var item in properties)
{
var customAttributes =
item.GetCustomAttributes(typeof(DependencyAttribute), false) as DependencyAttribute\[\];
if (customAttributes != null)
{
Type t = item.PropertyType;
RegisterInfo info = ContainerDictionary\[t.FullName\];
info.LifeTime = customAttributes.FirstOrDefault().\_lifeTimeType;
var value = CreateObject(info.TargetType);
item.SetValue(objType, value);
}
}
//字段注入
var filds = type.GetFields().Where(f => f.IsDefined(typeof(DependencyAttribute), false)).ToList();
foreach (var fild in filds)
{
var attribute = fild.GetCustomAttribute(typeof(DependencyAttribute)) as DependencyAttribute;
if (attribute != null)
{
Type t = fild.DeclaringType;
RegisterInfo info = ContainerDictionary\[t.FullName\];
info.LifeTime = attribute.\_lifeTimeType;
var value = CreateObject(info.TargetType);
fild.SetValue(objType, value);
}
}
//方法注入
var methods = type.GetMethods().Where(m => m.IsDefined(typeof(InjectionMethodAttribute), false)).ToList();
List<object> paramrterList = new List<object>();
foreach (var item in methods)
{
var attribute = item.GetCustomAttribute(typeof(InjectionMethodAttribute)) as InjectionMethodAttribute;
if (attribute != null)
{
var parameters = item.GetParameters();
foreach (var parameter in parameters)
{
var paraType = parameter.ParameterType;
RegisterInfo info = ContainerDictionary\[paraType.FullName\];
Type targetType = info.TargetType;
object para = CreateTypeByRegisterType(info, targetType);
//递归:隐形的跳出条件,就是GetParameters结果为空,targetType拥有无参数构造函数
paramrterList.Add(para);
}
item.Invoke(objType, paramrterList.ToArray());
}
}
return objType;
}
private static readonly object obj = new object();
/// <summary>
/// 根据注入类别创建对象
/// </summary>
/// <param name="info"></param>
/// <param name="targetType"></param>
/// <returns></returns>
private object CreateTypeByRegisterType(RegisterInfo info, Type targetType)
{
object para = null;
switch (info.LifeTime)
{
case LifeTimeType.Transient:
para = this.CreateObject(targetType);
break;
case LifeTimeType.Singleton:
//需要线程安全 双if+lock
if (para == null)
{
lock (obj)
{
if (this.TypeObjectDictionary.ContainsKey(targetType))
{
para = this.TypeObjectDictionary\[targetType\];
}
else
{
if (para == null)
{
para = this.CreateObject(targetType);
this.TypeObjectDictionary\[targetType\] = para;
}
}
}
}
break;
case LifeTimeType.PerThread:
//线程单例:线程槽,把数据存在这里
{
string key = targetType.FullName;
object oValue = CallContext.GetData(key);
if (oValue == null)
{
para = this.CreateObject(targetType);
CallContext.SetData(key, para);
}
else
{
para = oValue;
}
}
break;
default:
throw new Exception("wrong LifeTime");
}
return para;
}
}
以上代码经过测试,可以使用。
public interface IImitateScene
{
void DoSomeThing();
}
public class ImitateScene: IImitateScene
{
private IUserService userService;
public ImitateScene(IUserService \_userService)
{
this.userService = \_userService;
}
\[Dependency(LifeTimeType.Transient)\]
public IShopService ShopService { get; set; }
public IStoreService StoreService { get; set; }
\[InjectionMethod(LifeTimeType.Transient)\]
public void SetStoreService(IStoreService \_storeService)
{
this.StoreService = \_storeService;
}
public void DoSomeThing()
{
this.userService.DoSomeThing();
this.StoreService.DoSomeThing();
this.ShopService.DoSomeThing();
}
}
附上项目图,项目结构只为了测试,未做过设计,嘿嘿
测试结果:
基本代码就在这里了,还有很多功能未完善,后续有时间会努力研究完善它,造造轮子。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章