Unity Application Block 1.0系列(1): 快速开始

Unity Application Block (Unity) 是微软 Patterns & Practices  团队开发的一个轻量级、可扩展的依赖注入容器,有助于构建松散耦合的系统。它支持构造子注入 (Constructor Injection) , 属性/设值方法注入 (Property/Setter Injection) 和方法调用注入 (Method Call Injection) 。Patterns & Practices  团队于前些天(4月4日)发布了Unity的第一个正式版本(Unity 1.0)。

准备工作

先看一些接口和类,下面会用到:

Unity 1-4.jpg

 

public interface IPlayer
{
    
void Play();
}

public class Mp3Player : IPlayer
{
    
public void Play()
    {
        Console.WriteLine(
"Playing Mp3");
    }
}

public class CDPlayer : IPlayer
{
    
public void Play()
    {
        Console.WriteLine(
"Playing CD");
    }
}

public class DVDPlayer : IPlayer
{
    
public void Play()
    {
        Console.WriteLine(
"Playing DVD");
    }
}


以一个简单的例子开始

//创建Unity容器
IUnityContainer container = new UnityContainer();

//注册类型映射
container.RegisterType<IPlayer, Mp3Player>();

//获取对象实例,由于上一步已在容器中将IPlayer接口映射为Mp3Player类,
//所以这里会自动装载Mp3Player类,创建该类的实例
IPlayer player = container.Resolve<IPlayer>();

//调用实例方法
player.Play();


输出为:

Unity 1-1.jpg

注册映射

在Unity中可以通过两种方式来为Container注册映射:

1. RegisterType:

在容器中注册“接口”( 包括 Interface 和 Base Class )  到“具体类”的映射。在需要的时候 ( 如上例中container.Resolve<IPlayer>() ) ,容器会根据指定的接口创建它所映射的具体类的实例。

如:

//注册IPlay接口映射为Mp3Player类
container.RegisterType<IPlayer, Mp3Player>();

//注册BasePlay基类映射为Mp3Player类
container.RegisterType<BasePlayer, Mp3Player>();

一个接口可能会映射多个具体类,可以为每个映射指定Name,如:

container.RegisterType<IPlayer, Mp3Player>("myMp3Player1");

RegisterType有以下几个重载方法:

RegisterType<TFrom, TTo>( )
RegisterType<TFrom, TTo>(LifetimeManager lifetime)
RegisterType<TFrom, TTo>(String name)
RegisterType<TFrom, TTo>(String name, LifetimeManager lifetime)
RegisterType<T>(LifetimeManager lifetime)
RegisterType<T>(String name, LifetimeManager lifetime)
RegisterType(Type from, Type to)
RegisterType(Type from, Type to, String name)
RegisterType(Type from, Type to, LifetimeManager lifetime)
RegisterType(Type from, Type to, String name, LifetimeManager lifetime)
RegisterType(Type t, LifetimeManager lifetime)
RegisterType(Type t, String name, LifetimeManager lifetime)

关于LifttimeManager可以参考下面文章:

Unity Application Block 1.0系列(7): Lifetime Managers

2. RegisterInstance:

在容器中注册“接口”( 包括 Interface 和 Base Class )  到“实例”的映射。

Mp3Player mp3Player = new Mp3Player();

//注册IPlayer接口映射为mp3Player实例
container.RegisterInstance<IPlayer>(mp3Player);

同样的也可以为该映射指定Name,如:

container.RegisterInstance<IPlayer>("myMp3Player", mp3Player);

RegisterInstance有以下几个重载方法:

RegisterInstance<TInterface>(TInterface instance)
RegisterInstance<TInterface>(TInterface instance, LifetimeManager lifetime)
RegisterInstance<TInterface>(String name, TInterface instance)
RegisterInstance<TInterface>(String name, TInterface instance, LifetimeManager lifetime)
RegisterInstance(Type t, Object instance)
RegisterInstance(Type t, Object instance, LifetimeManager lifetime)
RegisterInstance(Type t, String name, Object instance)
RegisterInstance(Type t, String name, Object instance, LifetimeManager lifetime)

获取对象实例

在Unity中通过Resolve方法获取映射的类的对象实例。

回到本文开始的那个例子,看这行代码:
IPlayer player = container.Resolve<IPlayer>();

这里就是通过Resolve方法获取IPlayer接口所映射的Mp3Player的实例。

继续看下面的代码:

IUnityContainer container = new UnityContainer();

container.RegisterType
<IPlayer, Mp3Player>();
container.RegisterType
<IPlayer, CDPlayer>();

IPlayer player 
= container.Resolve<IPlayer>();
player.Play();

这里为IPlayer接口注册两个映射类:Mp3Player和CDPlayer。通过Resolve方法获取到的这个player对象是Mp3Player还是CDPlayer的实例呢?

看看运行结果:

Unity 1-2.jpg

Unity中当遇到一个接口映射到多个具体类情况时,Resolve时候使用最后注册的映射。

所以上面输出结果为 "Playing CD"  就不足为怪。


再继续看一个例子:

IUnityContainer container = new UnityContainer();

container.RegisterType
<IPlayer, Mp3Player>();

//
注册时指定Name为"myCDPlayer"
container.RegisterType<IPlayer, CDPlayer>("myCDPlayer");

IPlayer player1 
= container.Resolve<IPlayer>("myCDPlayer");
IPlayer player2 
= container.Resolve<IPlayer>();

player1.Play();
player2.Play();

这时候player1和player2各表示哪个类的实例呢?

看看输出结果:

Unity 1-3.jpg

可以看出Resolve方法可以通过指定Name( 这个Name值对应着RegisterType时指定的Name值 ),通过这种方式可以获取到指定的对象实例。所以当一个接口映射到多个具体类时,还是很有必要为这些映射指定Name。

注意:Name值为大小写敏感的。

上面的player2对象由于Resolve时候没有指定Name,则使用默认的映射关系(RegisterType或RegisterInstance时如果不指定Name,则这个映射就为该接口的默认映射,如果有多个这样的默认映射,还是按照那个规则,以最后一个有效)。

继续再来看一个例子:

IUnityContainer container = new UnityContainer();

container.RegisterType
<IPlayer, Mp3Player>("myCDPlayer");
container.RegisterType
<IPlayer, CDPlayer>("myCDPlayer");

IPlayer player 
= container.Resolve<IPlayer>("myCDPlayer");

player.Play();

输出为:
Unity 1-2.jpg

可以看出这个还是满足刚才说的那个原则:
“Unity中当遇到一个接口映射到多个具体类情况时,Resolve时候使用最后注册的映射”

看一下Resolve的重载方法:

Resolve<T>( )
Resolve<T>(string name)
Resolve(Type t)
Resolve(Type t, string name)

获取所有对象实例

可以通过ResolveAll方法来获取指定接口的所有对象实例:

IUnityContainer container = new UnityContainer();

container.RegisterType
<IPlayer, Mp3Player>("myMP3Player");
container.RegisterType
<IPlayer, CDPlayer>("myCDPlayer");
container.RegisterType
<IPlayer, DVDPlayer>();

IEnumerable
<IPlayer> players = container.ResolveAll<IPlayer>();

foreach (IPlayer player in players)
{
    player.Play();
}


输出结果为:
Unity 1-3.jpg

例子中为IPlayer接口映射了三个具体类,但是通过输出的结果发现,只有输出CD和MP3的,也就是players对象就只包含CDPlayer和MP3Player的实例,为什么会出现这种情况?

Untiy中ResolveAll方法只是返回注册映射时有指定Name的所有类的实例。

所以不难看出上例中虽然有为IPlayer接口映射了三个具体类,但是由于RegisterType<IPlayer, DVDPlayer>()时没指定Name,所以通过ResolveAll方法获取不到该实例。

ResolveAll有以下两个重载方法:

ResolveAll<T>( )
ResolveAll(Type t)

作者:Inrie (洪晓军)
出处:http://www.cnblogs.com/inrie

posted on 2008-04-18 00:01  Inrie  阅读(3569)  评论(14编辑  收藏  举报