UnityTest
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>();
IDataProcessor p1 = container.Resolve<IDataProcessor>();
IDataProcessor p2 = container.Resolve<IDataProcessor>();
Console.WriteLine(p1 == p2);
输出我们看到false, 默认情况下每次创建一个新的实例,如果想要单一实例怎么办,在Cotain里有一个LifetimeManager概念,
看源代码列出主要有以下几种:
TransientLifetimeManager 即默认处理,容器完整创建对象后,不做任何处理
ContainerControlledLifetimeManager 容器持有,实现Singleton 模式
ExternallyControlledLifetimeManager 故名思意,自已外部管理对象生命周期,容器仅保存弱引用
PerThreadLifetimeManager 容器保证在每个线程中存在一个对象实例
SynchronizedLifetimeManager 抽象类,暂没研究
先来试试ContainerControlledLifetimeManager,代码如下:
ContainerControlledLifetimeManagerTest
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>(new ContainerControlledLifetimeManager());
IDataProcessor p1 = container.Resolve<IDataProcessor>();
IDataProcessor p2 = container.Resolve<IDataProcessor>();
Console.WriteLine(p1 == p2);
Console.ReadLine();
可以看到返回的是同一实例. OK,再来看看ExternallyControlledLifetimeManager,直接替换ContainerControlledLifetimeManager,
ExternallyControlledLifetimeManager
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>(new ExternallyControlledLifetimeManager());
IDataProcessor p1 = container.Resolve<IDataProcessor>();
IDataProcessor p2 = container.Resolve<IDataProcessor>();
Console.WriteLine(p1 == p2);
Console.ReadLine();
结果是和ContainerControlledLifetimeManager一样的,仔细想想,当使用ExternallyControlledLifetimeManager时,
容器仅保存弱引用(可被垃圾回收),意味着可能是单一实例(没有回收)可能不是.
接下来再试试PerThreadLifetimeManager,测试这个要费点周折,代码如下:
PerThreadLifetimeManagerTest
class Program
{
static IDataProcessor thread1stP1;
static IDataProcessor thread1stP2;
static IDataProcessor thread2ndP1;
static IDataProcessor thread2ndP2;
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>(new PerThreadLifetimeManager());
Thread t1 = new Thread(new ParameterizedThreadStart(InitProcessor1));
Thread t2 = new Thread(new ParameterizedThreadStart(InitProcessor2));
t1.Start(container);
t1.Join();
t2.Start(container);
t2.Join();
Console.WriteLine("Thread1stP1 == Thread2ndP1 " + (thread1stP1 == thread2ndP1));
Console.ReadLine();
}
static void InitProcessor1(Object c)
{
Console.WriteLine("Init in Thread1st");
UnityContainer contain = c as UnityContainer;
thread1stP1 = contain.Resolve<IDataProcessor>();
thread1stP2 = contain.Resolve<IDataProcessor>();
Console.WriteLine("thread1stP1 == thread1stP1 " + (thread1stP1 == thread1stP2));
}
static void InitProcessor2(Object c)
{
Console.WriteLine("Init in Thread2nd");
UnityContainer contain = c as UnityContainer;
thread2ndP1 = contain.Resolve<IDataProcessor>();
thread2ndP2 = contain.Resolve<IDataProcessor>();
Console.WriteLine("thread1stP1 == thread1stP1 " + (thread2ndP1 == thread2ndP2));
}
}
可以看到,在同一个线程内创建的实例是同一实例,线程外侧不是.
现在回到核心需求: 假设我们定义的抽象接口要map到多个具体类,要怎么处理?,Unity Contain在注册时提供一个命名注册,
即你可以给类型Map时命名,看以下代码:
NamedRegister
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>();
//命名注册
container.RegisterType<IDataProcessor, PrintDataProcessor>("Prompt");
container.RegisterType<IDataProcessor, PromptDataProcessor>("Print");
IDataProcessor prc3 = container.Resolve<IDataProcessor>("Prompt");
IDataProcessor prc4 = container.Resolve<IDataProcessor>("Print");
Console.WriteLine(prc3.GetType());
Console.WriteLine(prc4.GetType());
Console.ReadLine()
可以看到结果,输出分别是PrintDataProcessor 和 PromptDataProcessor类型.
这种Type + Name的设计来确定一种类型Map是非常灵活的,假设我们需要一个类型但两个实例处理不同方面的对象.
可以很容易实现,
Register a type as two Instance
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>();
//注册一个类型mapping但两个实例处理不同方面的对象.
container.RegisterType<IDataProcessor, PromptDataProcessor>("Customers", new ContainerControlledLifetimeManager());
container.RegisterType<IDataProcessor, PromptDataProcessor>("Orders", new ContainerControlledLifetimeManager());
IDataProcessor p1 = container.Resolve<IDataProcessor>("Customers");
IDataProcessor p2 = container.Resolve<IDataProcessor>("Customers");
IDataProcessor p3 = container.Resolve<IDataProcessor>("Orders");
IDataProcessor p4 = container.Resolve<IDataProcessor>("Orders");
//注册名不存在将throw ResolutionFailedException
Console.WriteLine(p1 == p2); //true
Console.WriteLine(p3 == p4); //true
Console.WriteLine(p1 == p3); //false
Console.ReadLine();
Unity Contain 支持instance 注册,这时感觉Contain 扮演 Service Locator的角色,
Register Instance Test
IUnityContainer container = new UnityContainer();
IDataProcessor processor = new PromptDataProcessor();
//注册instance,默认是ContainerControlledLifetimeManager,调用Resolve不会再发生依赖注入
container.RegisterInstance<IDataProcessor>(processor);
processor = null;
IDataProcessor p1 = container.Resolve<IDataProcessor>();
IDataProcessor p2 = container.Resolve<IDataProcessor>();
Console.WriteLine(p1 == p2);
Console.ReadLine();
现在测试一下UnityContainer的ResloveAll方法,依文档描述是返回 一个注册类型 的所有instance,测试代码如下:
ResolveAll Test
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>();
IEnumerable<IDataProcessor> list = container.ResolveAll<IDataProcessor>();
foreach (var type in list)
{
Console.WriteLine(type.ToString());
}
//list.count == 0,没有输入出结果
Console.ReadLine();
很奇怪没有输出结果,留意文档里说的,If the container does not contain any named (non-default) mappings for the specified type, it will return null (in C#) or Nothing .想想背后的设计: 如果不是命名注册,ResolveAll 其实没有意义,因为非命名注册,只能对应一个具体类,Resolve就够了. 命名注册才有可能一个接口对应到多个具类,改一下码再测试:
ResolveAll Test
IUnityContainer container = new UnityContainer();
container.RegisterType<IDataProcessor, PromptDataProcessor>("TestResolveAll");
IEnumerable<IDataProcessor> list = container.ResolveAll<IDataProcessor>();
foreach (var type in list)
{
//输出了PromptDataProcessor Type
Console.WriteLine(type.ToString());
}
Console.ReadLine();
下面来看看具体的依赖注入方式,依据文档描述,Unity具体支持三种依赖注入,Constructor injection,Property injection,Method Injection.首先来看Constructor injection.
Constructor Injection
构造函数注入方式有二种,其一是当创建对象只有一个构造函数时,自动依赖注入。其二是有多个构造函数时,使用InjectionConstructorAttribute,简单的先看:
Constructor Injection
class MyObject
{
public MyObject(MyDependentClassA depend)
{
depend.Write("I was injected by constructor.");
}
}
class MyDependentClassA
{
public void Write(String message)
{
Console.WriteLine("In MyDependentClassA:" + message);
}
}
class MyDependentClassB
{
public void Write(String message)
{
Console.WriteLine("In MyDependentClassB:" + message);
}
}
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer()
.RegisterType<MyDependentClassA>()
.RegisterType<MyDependentClassB>()
.RegisterType<MyObject>();
MyObject ob = container.Resolve<MyObject>();
//输出:In MyDependentClassA:I was injected by constructor.
Console.ReadLine();
}
看看有两个构造函数并用InjectionConstructor指定注入
Constructor Injection
class MyObject
{
public MyObject(MyDependentClassA depend)
{
depend.Write("I was injected by constructor.");
}
[InjectionConstructor]
public MyObject(MyDependentClassB depend)
{
depend.Write("I was injected by constructor.");
}
}
class MyDependentClassA
{
public void Write(String message)
{
Console.WriteLine("In MyDependentClassA:" + message);
}
}
class MyDependentClassB
{
public void Write(String message)
{
Console.WriteLine("In MyDependentClassB:" + message);
}
}
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer()
.RegisterType<MyDependentClassA>()
.RegisterType<MyDependentClassB>()
.RegisterType<MyObject>();
MyObject ob = container.Resolve<MyObject>();
//输出:In MyDependentClassB:I was injected by constructor.
Console.ReadLine();
}
现在假设构造函数依赖一个抽象一个特定的interface,
Constructor Injection
interface IMyDepended
{
void Write(String message);
}
class MyDependentClassA : IMyDepended
{
public void Write(String message)
{
Console.WriteLine("In MyDependentClassA:" + message);
}
}
class MyDependentClassB : IMyDepended
{
public void Write(String message)
{
Console.WriteLine("In MyDependentClassB:" + message);
}
}
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer()
.RegisterType<IMyDepended,MyDependentClassA>()
.RegisterType<MyObject>();
//constructor injection
MyObject ob = container.Resolve<MyObject>();
//输出:In MyDependentClassA:I was injected by constructor.
Console.ReadLine();
}
PropertyInjection
实现只有一种方式,通过给相应的属性标识为Dependency
PropertyInjection
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IMyDependend, MyDependentClass>(new ContainerControlledLifetimeManager())
.RegisterType<MyObject>();
MyObject ob = container.Resolve<MyObject>();
//输出I was injected by property.
Console.ReadLine();
}
}
class MyObject
{
private IMyDependend _propertyInjector;
[Dependency]
public IMyDependend PropertyInjector
{
get
{
return this._propertyInjector;
}
set
{
this._propertyInjector = value;
this._propertyInjector.Write("I was injected by property.");
}
}
}
interface IMyDependend
{
void Write(String message);
}
class MyDependentClass:IMyDependend
{
public MyDependentClass()
{
}
public void Write(String message)
{
Console.WriteLine(message);
}
}
Method Injection
实现也只有一种方式, 把相应的注入方法标识为InjectionMethod
InjectionMethod
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IMyDependend, MyDependentClass>(new ContainerControlledLifetimeManager())
.RegisterType<MyObject>();
MyObject ob = container.Resolve<MyObject>();
//输出I was injected by method.
Console.ReadLine();
}
}
class MyObject
{
[InjectionMethod]
public void Init(MyDependentClass depend)
{
depend.Write("I was injected by method.");
}
}
interface IMyDependend
{
void Write(String message);
}
class MyDependentClass:IMyDependend
{
public MyDependentClass()
{
}
public void Write(String message)
{
Console.WriteLine(message);
}
}
Buildup方法
如果你已经有一个对象,但在每次使用前想使初始化一次,可以使用BuildUp方法达到这个目的.
BuildUp
class Program
{
static void Main(string[] args)
{
IUnityContainer container = new UnityContainer();
container.RegisterType<IMyDependend, MyDependentClass>(new ContainerControlledLifetimeManager())
.RegisterType<MyObject>(new ContainerControlledLifetimeManager());
MyObject ob = container.Resolve<MyObject>();
MyObject ob2 = container.BuildUp<MyObject>(ob);
/**//*输出
I was injected by constructor.
I was injected by property.
I was injected by method.
I was injected by property.
I was injected by method.
*/
Console.ReadLine();
}
}
class MyObject
{
public MyObject(IMyDependend depend)
{
depend.Write("I was injected by constructor.");
}
[InjectionMethod]
public void Init(IMyDependend depend)
{
depend.Write("I was injected by method.");
}
[Dependency]
public IMyDependend PropertyDepend
{
set
{
value.Write("I was injected by property.");
}
}
}
interface IMyDependend
{
void Write(String message);
}
class MyDependentClass:IMyDependend
{
public MyDependentClass()
{
}
public void Write(String message)
{
Console.WriteLine(message);
}
}
Reference:
First Steps with Unity
http://www.nablasoft.com/alkampfer/index.php/2009/01/16/first-steps-with-unity/
IoC框架介绍
http://blog.csdn.net/wanghao72214/archive/2009/03/08/3969594.aspx
Martin Fowler的介绍文章
http://martinfowler.Mcom/articles/injection.html