博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Unity Ioc 学习笔记1
阅读量:5072 次
发布时间:2019-06-12

本文共 8877 字,大约阅读时间需要 29 分钟。

原文:

Unity Ioc 介绍:

Unity是微软团队开发的一个轻量级,可扩展的依赖注入容器,为松散耦合应用程序提供了很好的解决方案,支持构造器注入,属性注入,方法注入。同时因为把对象交给容器创建,有没有可能在创建的时候做些手脚和功能呢?答案是肯定的。

目前Unity中提供两个Lifetime Manager类可供我们直接使用,当然你也可以实现自己的Lifetime Manager类。

1. ContainerControlledLifetimeManager 
Unity保存一个指向对象实例的引用。通过Unity容器为同一个类型或对象获取对象实例时,每次获取到的都是同一个实例。也就是说实现了对象单例模式。默认情况下,RegisterInstance方法使用该Lifetime Manager。
2. ExternallyControlledLifetimeManager 
Unity仅保存一个指向对象实例的弱引用。通过Unity容器为同一个类型或对象获取对象实例时,每次获取到的都是同一个实例。但是由于当对象创建完之后,容器没有对该对象的强引用,所以就可能出现当其他地方没有去强引用它时候,会被GC回收掉。
先看看一个接口和类,下面会用到

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

接下来通过在RegisterType和RegisterInstance时指定相应的Lifetime Manager来介绍Lifetime Manager的应用场景。
1. RegisterType
当用RegisterType注册映射关系时,如果没有指定LifetimeManager,默认是使用一个瞬态的Lifetime Manager。即每次通过Unity容器获取对象的实例时都会重新创建一个该实例,也就是说Unity容器不存在一个到该对象的引用。
看一个例子:

 

IUnityContainer container  =   new  UnityContainer();
container.RegisterType < IPlayer, Mp3Player > ();
IPlayer player1  =  container.Resolve < IPlayer > ();
Console.WriteLine( string .Format( " Player1 HashCode: {0} " ,player1.GetHashCode()));
IPlayer player2  =  container.Resolve < IPlayer > ();
Console.WriteLine( string .Format( " Player2 HashCode: {0} " ,player2.GetHashCode()));

输出结果:

Unity 7-1.jpg
通过输出的player1和player2对象的HashCode值可以看出,player1和player2分别是Mp3Player类的不同实例。
那怎样实现单例模式呢?
要实现单例模式,容器需要保存一个指向对象实例的引用。通过在RegisterType时为它指定相应的Lifetime Manager可以实现单例模式,从上面对ContainerControlledLifetimeManager和ExternallyControlledLifetimeManager的介绍可以知道,这两个Lifetime Manager都可以支持单例模式。
修改上面的代码为:

IUnityContainer container  =   new  UnityContainer();
// 这里指定使用ContainerControlledLifetimeManager对象
container.RegisterType < IPlayer, Mp3Player > (
new
 ContainerControlledLifetimeManager());
IPlayer player1  =  container.Resolve < IPlayer > ();
Console.WriteLine( string .Format( " Player1 HashCode: {0} " ,player1.GetHashCode()));
IPlayer player2  =  container.Resolve < IPlayer > ();
Console.WriteLine( string .Format( " Player2 HashCode: {0} " ,player2.GetHashCode()));

看看输出:
Unity 7-2.jpg
通过输出结果可以看出,player1和player2对象为Mp3Player类的同一实例,指向同一内存地址。
2. RegisterInstance
当用RegisterInstance注册映射关系时,如果没有指定Lifetime Manager,默认是使用ContainerControlledLifetimeManager,即支持单例模式。
看个例子:

IUnityContainer container  =   new  UnityContainer();
IPlayer mp3Player  =   new  Mp3Player();
container.RegisterInstance < IPlayer > (mp3Player);
IPlayer player1  =  container.Resolve < IPlayer > ();
Console.WriteLine( string .Format( " Player1 HashCode: {0} " , player1.GetHashCode()));
IPlayer player2  =  container.Resolve < IPlayer > ();
Console.WriteLine( string .Format( " Player2 HashCode: {0} " , player2.GetHashCode()));

看看输出:
Unity 7-3.jpg
通过输出结果可以看出,player1和player2对象为Mp3Player类的同一实例,指向同一内存地址。

 

Unity是微软P&P部门开发的一个轻量级IoC框架,通过Interception机制可以实现基于三种拦截机制的AOP。不过Unity仅仅提供“显式”拦截机制,以致我们为了注册可被拦截的类型会多写很多代码和配置。本篇文章通过UnityContainer的扩展提供了一种“自动”拦截机制。

一、显式拦截

我们通过一个简单的实例演示Unity原生支持的显式拦截机制和我们通过扩展实现的自动拦截机制。我们定了如下一个简单的SimpleCallHandler,在Invoke方法中通过在控制台打印一段文字用以证明应用在某个类型上的CallHandler被执行了。

1: public class SimpleCallHandler : ICallHandler
2: {
3:     public IMethodReturn Invoke(IMethodInvocation input, GetNextHandlerDelegate getNext)
4:     {
5:         Console.WriteLine("The CallHandler applied to \"{0}\" is invoked.", input.Target.GetType().Name);
6:         return getNext()(input, getNext);
7:     }
8:     public int Order { get; set; }
9: }
10: public class SimpleCallHandlerAttribute : HandlerAttribute
11: {
12:     public override ICallHandler CreateHandler(IUnityContainer container)
13:     {
14:         return new SimpleCallHandler { Order = this.Order };
15:     }
16: }

然后我们创建了如下所示的一个接口IFoo和三个类Foo、Bar和Baz。其中Foo实现了接口IFoo,而Foo依赖于Bar,Bar依赖于Baz。我们以构造器注入的方式定义Foo和Bar。SimpleCallHandler被同时应用到了Foo、Bar和Baz的DoSth方法上。

1: public interface IFoo
2:    {
3:        void DoSth();
4:    }
5: 
6:    public class Foo : IFoo
7:    {
8:        public Bar Bar { get; private set; }
9:        public Foo(Bar bar)
10:        {
11:            this.Bar = bar;
12:        }
13:        [SimpleCallHandler]
14:        public virtual void DoSth()
15:        {
16:            this.Bar.DoSth();
17:        }
18:    }
19:    public class Bar : MarshalByRefObject
20:    {
21:        public Baz Baz { get; private set; }
22:        public Bar(Baz baz)
23:        {
24:            this.Baz = baz;
25:        }
26:        [SimpleCallHandler]
27:        public virtual void DoSth()
28:        {
29:            this.Baz.DoSth();
30:        }
31:    }
32:    public class Baz : MarshalByRefObject
33:    {
34:        [SimpleCallHandler]
35:        public void DoSth()
36:        {
37:            Console.WriteLine("Done...");
38:        }
39:    }

所谓显式拦截就是说:如果某个类型需要被拦截处理,比如将其显式地注册为“可被拦截的类型”,并且需要显式地注册拦截器(决定拦截机制)和拦截行为。对于本实例来说,为了上应用在Foo、Bar和Baz上的CallHandler能够起作用,我们需要通过如下的方式对这三个类型进行显式地拦截注册。

1: IUnityContainer container = new UnityContainer();
2: container.AddNewExtension
()
3:     .RegisterType
(new Interceptor
(), new InterceptionBehavior
())
4:     .RegisterType
(new Interceptor
(), new InterceptionBehavior
())
5:     .RegisterType
(new Interceptor
(), new InterceptionBehavior
());
6: 
7: IFoo foo = container.Resolve
();
8: foo.DoSth();

运行结果:

1: The CallHandler applied to "Foo" is invoked.
2: The CallHandler applied to "Bar" is invoked.
3: The CallHandler applied to "Baz" is invoked.
4: Done...

二、自动拦截

如果通过我们自定义的UnityContainer扩展AutoInterception,你就无须对需要被拦截的类型进行显式注册。而相关的代码将会变得简单,运行如下一段代码,你依然会得到同上面一样的结果。

1: IUnityContainer container = new UnityContainer();
2: container.AddNewExtension
()
3:     .AddNewExtension
()
4:     .RegisterType
();
5: 
6: IFoo foo = container.Resolve
();
7: foo.DoSth();

三、应用不同的拦截机制

在默认的情况下,AutoInterception采用的拦截器为TransparentProxyInterceptor。我们通过通过配置AutoInterception的方式来应用其它两种拦截器,即InterfaceInterceptor和VirtualMethodInterceptor。由于在下面的代码中采用了InterfaceInterceptor,所有只有实现了IFoo接口的Foo对象才会被拦截。

1: IUnityContainer container = new UnityContainer();
2: container.AddNewExtension
()
3:     .AddNewExtension
()
4:     .Configure < AutoInterception>().RegisterInterceptor(new InterfaceInterceptor())
5:     .RegisterType
();
6: 
7: IFoo foo = container.Resolve
();
8: foo.DoSth();

执行结果:

1: The CallHandler applied to "Foo" is invoked.
2: Done...

如果我们采用VirtualMethodInterceptor的话,只有定义在需方法的Foo和Bar的DoSth方法才会被拦截。

1: IUnityContainer container = new UnityContainer();
2: container.AddNewExtension
()
3:     .AddNewExtension
()
4:     .Configure < AutoInterception>().RegisterInterceptor(new VirtualMethodInterceptor())
5:     .RegisterType
();
6: 
7: IFoo foo = container.Resolve
();
8: foo.DoSth();

输出结果:

1: The CallHandler applied to "Wrapped_Foo_6c22528df1b64d3886e9955cd8961ca7" is invoked.
2: The CallHandler applied to "Wrapped_Bar_c10e3640a27d469c8872ec4193303897" is invoked.
3: Done...

四、支持配置

AutoInterception不仅仅支持Unity提供的Policy Injection配置,还可以通过配置指定采用的拦截器类型。现在我们将应用在Foo、Bar和Baz上的SimpleCallHandlerAttribute特性全部删除,通过如下的配置将该CallHandler应用到所有的DoSth方法上。这个配置还指定了采用的拦截器类型为VirtualMethodInterceptor。

1: 
2: 
3:   
4:     
5:              type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection, Microsoft.Practices.Unity.Configuration"/>
6:     
7:   
8:     
9:     
10:     
11:     
12:     
13:     
14:       
15:       
16:       
17:       
18:         
19:           
20:             
21:               
22:             
23:           
24:           
25:         
26:       
27:       
28:         
29:       
30:     
31:   
32: 

我们通过如下的代码,通过加载配置的方式来配置创建的UnityContainer。最终直接通过解析接口IFoo得到Foo对象,并调用其DoSth方法。

1: IUnityContainer container = new UnityContainer();
2: UnityConfigurationSection unitySettings = (UnityConfigurationSection)ConfigurationManager.GetSection(UnityConfigurationSection.SectionName);
3: unitySettings.Configure(container);
4: IFoo foo = container.Resolve
();
5: foo.DoSth();

由于我们采用的是VirtualMethodInterceptor,所有只有Foo和Bar中定义的需方法才能被拦截,这可以通过如下的输出结果得到证实:

1: The CallHandler applied to "Wrapped_Foo_53c9f355fbac4acdaf405b2a92d0bd7a" is invoked.
2: The CallHandler applied to "Wrapped_Bar_8cdbf768e96c434da36ed1f181c2d6cd" is invoked.
3: Done...

虽然AutoInterception实现的逻辑并不复杂,但是对于不了解Unity设计的人来说也不是那么容易理解的。所以我并不打算介绍其内部原理,又兴趣的读者可以从

下载源代码。

转载于:https://www.cnblogs.com/luofuxian/archive/2013/05/05/3060791.html

你可能感兴趣的文章
八字案例董易奇
查看>>
二代CMS旅游网站程序V1使用手册(八):邮件发送系统配置管理
查看>>
Docker-基本使用
查看>>
ghost xp 安装IIS,并配置WCF
查看>>
iframe父子页面通信
查看>>
小写金额转中文大写金额
查看>>
【转】Sqlserver通过链接服务器访问Oracle的那些事儿!
查看>>
Javascript核心概述 - 深入了解javascript
查看>>
ambari 大数据安装利器
查看>>
java 上传图片压缩图片
查看>>
magento 自定义订单前缀或订单起始编号
查看>>
ACM_拼接数字
查看>>
计算机基础作业1
查看>>
Ubuntu 深度炼丹环境配置
查看>>
C#中集合ArrayList与Hashtable的使用
查看>>
js里=、== 和===有什么区别?
查看>>
从一个标准 url 里取出文件的扩展名
查看>>
map基本用法
查看>>
爬虫系列1:Requests+Xpath 爬取豆瓣电影TOP
查看>>
String与StringBuffer的区别
查看>>