(转)[EntLib]微软企业库5.0 学习之路——第十步、使用Unity解耦你的系统—PART2——了解Unity的使用方法(3)
2010-11-29 17:49
746 查看
原文地址:/article/4792193.html
今天继续介绍Unity,在上一篇的文章中,我介绍了使用UnityContainer来注册对象之间的关系、注册已存在的对象之间的关系,同时着重介绍了Unity内置的各种生命周期管理器的使用方法,今天则主要介绍Unity的Register和Resolve的一些高级应用。
本篇文章将主要介绍:
1、注册类型同时初始化构造函数参数并重载调用。
2、注册类型同时初始化属性参数并重载调用。
3、延迟获取对象。
4、检索检索容器中注册信息。
今天继续介绍Unity,在上一篇的文章中,我介绍了使用UnityContainer来注册对象之间的关系、注册已存在的对象之间的关系,同时着重介绍了Unity内置的各种生命周期管理器的使用方法,今天则主要介绍Unity的Register和Resolve的一些高级应用。
本篇文章将主要介绍:
2、注册类型同时初始化属性参数并重载调用。
3、延迟获取对象。
4、检索检索容器中注册信息。
[b]一、注册类型同时初始化构造函数参数并重载调用[/b]
我们在使用Unity中注册对象之间的关系时,可能对象有相应的构造函数,构造函数中需要传递相应的参数,Unity就支持这样的注册,其主要靠InjectionConstructor这个类来完成,我们首先来看下具体的类构造函数:
1 | public YourClass( string test,MyClassmy) |
2 | { |
3 | Console.WriteLine(test); |
4 | Console.WriteLine(my.ToString()); |
5 | } |
1 | //由于所注册的对象的有带有参数的构造函数,所以注册类型时需要提供相应的参数 |
2 | //这边采用InjectionConstructor这个类来实现 |
3 | container.RegisterType<IClass,YourClass>( |
4 | new InjectionConstructor( "a" , new MyClass())); |
5 | Console.WriteLine( "-----------默认调用输出-------------" ); |
6 | container.Resolve<IClass>(); |
在Unity中,已经帮我们解决了这个问题,我们可以通过ParameterOverride和ParameterOverrides来实现,其中ParameterOverride是针对一个参数,而ParameterOverrides是针对参数列表,有关注册参数初始化及参数重载的全部代码如下:
01 | public static void ResolveParameter() |
02 | { |
03 | //由于所注册的对象的有带有参数的构造函数,所以注册类型时需要提供相应的参数 |
04 | //这边采用InjectionConstructor这个类来实现 |
05 | container.RegisterType<IClass,YourClass>( |
06 | new InjectionConstructor( "a" , new MyClass())); |
07 | Console.WriteLine( "-----------默认调用输出-------------" ); |
08 | container.Resolve<IClass>(); |
09 |
10 | Console.WriteLine( "-----------重载后调用输出-------------" ); |
11 | //以下2种Resolve方法效果是一样的 |
12 | //对于参数过多的时候可以采用第2种方法,如果参数仅仅只有1个可以用第1种 |
13 | //container.Resolve<IClass>(newParameterOverride("test","test"), |
14 | //newParameterOverride("my","newMyClass").OnType<MyClass>()); |
15 | container.Resolve<IClass>( new ParameterOverrides() |
16 | { |
17 | { "test" , "test" }, |
18 | { "my" , new MyClass()} |
19 | }.OnType<YourClass>()); |
20 | } |
2、在使用ParameterOverrides进行重载参数时,可以使用如上面代码的方式进行指定,但是同样需要使用OnType来指定,不过这个的OnType指定的类型是注册的对象类型。
可以看出,其中第一个字符串参数在重载后调用时已经发生了更改。
[b]二、注册类型同时初始化属性并重载调用[/b]
这个初始化属性和上面的初始化参数很类似,只不过不同的是,属性的注册初始化是使用InjectionProperty,而重载属性是使用的PropertyOverride和PropertyOverrides,其使用方法也是相同的,这边就不多介绍了,代码如下:
01 | public static void ResolveProperty() |
02 | { |
03 | //注册对象关系时初始化对象的属性 |
04 | container.RegisterType<IClass,MyClass>( |
05 | new InjectionProperty( "Name" , "A班" ), |
06 | new InjectionProperty( "Description" , "A班的描述" )); |
07 | Console.WriteLine( "-----------默认调用输出-------------" ); |
08 | Console.WriteLine(container.Resolve<IClass>().Name); |
09 | Console.WriteLine(container.Resolve<IClass>().Description); |
10 | Console.WriteLine( "-----------重载后调用输出-------------" ); |
11 | //以下2种写法效果是一样的,同上面的构造函数参数重载 |
12 | //varmyClass=container.Resolve<IClass>(newPropertyOverride("Name","重载后的A班"), |
13 | //newPropertyOverride("Description","重载后的A班的描述")); |
14 | varmyClass=container.Resolve<IClass>( new PropertyOverrides() |
15 | { |
16 | { "Name" , "重载后的A班" }, |
17 | { "Description" , "重载后的A班的描述" } |
18 | }.OnType<MyClass>()); |
19 |
20 | Console.WriteLine(myClass.Name); |
21 | Console.WriteLine(myClass.Description); |
22 | } |
可以看到2个属性都已经被重载了。
Unity还为我们提供了一个DependencyOverride重载,其使用方法和参数重载、属性重载类似,这边就不演示了,不过需要注意的是DependencyOverride是针对所注册对象类型中所包含的对象类型重载,例如在A类中有构造函数参数是B类,同时也有个属性依赖于B类,当使用了DependencyOverride后,这个A对象原先注册的有关B类的依赖将全部改变。(具体可查看示例代码中的ResolveDependency)
[b]三、延迟获取对象[/b]
Unity还有个很不错的特性就是支持延迟获取,其本质是通过事先建立一个委托,然后再调用这个委托,看下下面的代码:
01 | public static void DeferringResolve() |
02 | { |
03 | varresolver=container.Resolve<Func<IClass>>(); |
04 |
05 | //根据业务逻辑做其他事情。 |
06 |
07 | //注册IClass与MyClass之间的关系 |
08 | container.RegisterType<IClass,MyClass>(); |
09 | //获取MyClass实例 |
10 | varmyClass=resolver(); |
11 |
12 | varresolver2=container.Resolve<Func<IEnumerable<IClass>>>(); |
13 |
14 | //根据业务逻辑做其他事情。 |
15 |
16 | //注册与IClass相关的对象。 |
17 | container.RegisterType<IClass,MyClass>( "my" ); |
18 | container.RegisterType<IClass,YourClass>( "your" ); |
19 | //获取与IClass关联的所有命名实例 |
20 | varclassList=resolver2(); |
21 | } |
2、第二种是事先通过Resolve<Func<IEnumerable<IClass>>>();来定义获取一个与IClass关联的命名实例列表的委托,然后调用相应的委托就可以一次性获取与IClass关联的所有命名实例。
这2种方式都很好的展示了Unity可以更加灵活的控制对象之间的注册与对象的调用。
[b]四、检索容器中注册信息[/b]
当我们在不断使用Unity容器的过程中,我们有时候想看一下容器中到底注册了多少对象,以及各个对象的一些信息,如:什么对象和什么对象关联、具体的注册名称和使用的生命周期管理器,这些信息都可以在容器的Registrations属性中查看到,在Unity文档中已经有个方法来查看这些信息了,代码如下:
01 | public static void DisplayContainerRegistrations(IUnityContainertheContainer) |
02 | { |
03 | string regName,regType,mapTo,lifetime; |
04 | Console.WriteLine( "容器中{0}个注册信息:" , |
05 | theContainer.Registrations.Count()); |
06 | foreach (ContainerRegistrationitem in theContainer.Registrations) |
07 | { |
08 | regType=item.RegisteredType.Name; |
09 | mapTo=item.MappedToType.Name; |
10 | regName=item.Name?? "[默认]" ; |
11 | lifetime=item.LifetimeManagerType.Name; |
12 | if (mapTo!=regType) |
13 | { |
14 | mapTo= "->" +mapTo; |
15 | } |
16 | else |
17 | { |
18 | mapTo= string .Empty; |
19 | } |
20 | lifetime=lifetime.Substring(0,lifetime.Length- "生命周期管理器" .Length); |
21 | Console.WriteLine( "+{0}{1}'{2}'{3}" ,regType,mapTo,regName,lifetime); |
22 | } |
23 | } |
01 | public static void RegisterAll() |
02 | { |
03 | container.RegisterType<IClass,MyClass>( "my" ); |
04 | container.RegisterType<IClass,YourClass>( "your" , |
05 | new ExternallyControlledLifetimeManager()); |
06 | container.RegisterType<ISubject,Subject1>( "subject1" ); |
07 | container.RegisterType<ISubject,Subject2>( "subject2" ); |
08 |
09 | DisplayContainerRegistrations(container); |
10 | } |
可以看到,我在代码中注册的信息都已经很好的反应出来了。
同时如果想查看某个对象是否已经被注册,可以通过container.IsRegistered<T>来验证,这边就不演示了。
以上就是本文的所有内容了,主要介绍了Unity的Register和Resolve的一些高级应用,英文好的朋友可以直接查看Unity的官方文档。
示例代码下载:
(注意:本文示例代码是基于VS2010+Unity2.0,所以请使用VS2010打开,如果没有安装VS2010,请将相关代码复制到相应的VS中运行既可)
[b]微软企业库5.0学习之路系列文章索引:[/b]
扩展学习: