程序员人生 网站导航

通过fsharp 使用Enterprise Library Unity 3 - 三种拦截模式的探索

栏目:互联网时间:2014-11-04 08:43:47
这篇就3种拦截模式进行1下探索。
                                      

特性总结

  类型 特点 其他
InterfaceInterceptor Innstance 仅单接口 类内部函数相互援用也能没法引发拦截行动
TransparentProxyInterceptor           Instance 多接口(接口之间可以切换)  MarshalByRef 运行缓慢 接口类型(virtual, non-virtual, or interface) 类内部函数相互援用也能没法引发拦截行动
VirtualMethodInterceptor                                                   Type  多接口                                  不能用在已有对象上,接口函数必须为virtual 类内部函数相互援用也能引发拦截行动


回想1下类的声明,两个接口,1个实现。fsharp实现接口函数的方法与csharp其实不完全1致,会造成1些实现上的困扰,这在后面会提到。
type ITenantStore = abstract member Msg : unit->unit type TenantStore() as x= //do printfn "new TenantStore %A" (x.GetHashCode()) interface ITenantStore with member this.Msg() = printfn "Hello, it's TenantStore" interface IDisposable with member this.Dispose() = printfn "TenantStore hase been cleaned"

下面进行1些测试。
let showregistrations (container:UnityContainer) = container.Registrations |> Seq.iter (fun i -> printfn "Regist Type:%A" i.RegisteredType) using(new UnityContainer())(fun ctner-> ctner.AddNewExtension<Interception>() |> ignore ctner.RegisterType<ITenantStore, TenantStore>(new Interceptor<TransparentProxyInterceptor>(),//后续对此注入策略进行切换 new InterceptionBehavior<LogingInterceptionBehavior>()) |> ignore showregistrations ctner let t = ctner.Resolve<ITenantStore>() t.Msg())

showregistrations 显示已注册的类型,用来展现注册内部的信息。另外,在交互式代码中使用using相较于use更加的适合,FSI声明的对象的生命周期是全局的,在做实验的时候没法控制container,反复清环境不太方便。

TransparentProxyInterceptor的结果

Regist Type:Microsoft.Practices.Unity.IUnityContainer Regist Type:Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy Regist Type:FSI_0002+ITenantStore From the logging interceptor: "Invoke method System.Type GetType():System.Object at 16:20:45" From the logging interceptor: "Method System.Type GetType():System.Object returned FSI_0002+TenantStore at 16:20:45" From the logging interceptor: "Invoke method Void Msg():FSI_0002+ITenantStore at 16:20:45" Hello, it's TenantStore From the logging interceptor: "Method Void Msg():FSI_0002+ITenantStore returned at 16:20:45" val it : unit = ()

InterfaceInterceptor的结果
Regist Type:Microsoft.Practices.Unity.IUnityContainer Regist Type:Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy Regist Type:FSI_0002+ITenantStore From the logging interceptor: "Invoke method Void Msg():FSI_0002+ITenantStore at 16:22:54" Hello, it's TenantStore From the logging interceptor: "Method Void Msg():FSI_0002+ITenantStore returned at 16:22:54" val it : unit = ()
虽然对象有两个接口,IDiposable接口和ITenantStore接口,拦截依然成功了,所以支持多对象指的是接口之间的切换,并不是不支持实现多对象的类。


VirtualMethodInterceptor的结果
Regist Type:Microsoft.Practices.Unity.IUnityContainer Regist Type:Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy Regist Type:FSI_0002+ITenantStore Hello, it's TenantStore val it : unit = ()

拦截失败。 研究后发觉是由于Fsharp中其实不直接支持Virtual方法,Fsharp实现接口成员,默许为显示(explicit)实现,想要申明Virtual方法需要1些技能。
可参考http://cs.hubfs.net/topic/None/73936


再定义1个测试类来试试VirtualMethodInterceptor。
type testClass() = abstract member Test : unit -> unit default x.Test() = printfn "hello " using(new UnityContainer())(fun ctner-> ctner.AddNewExtension<Interception>() |> ignore ctner.RegisterType<testClass>(new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<LogingInterceptionBehavior>()) |> ignore showregistrations ctner let t = ctner.Resolve<testClass>() t.Test() )

结果
Regist Type:Microsoft.Practices.Unity.IUnityContainer Regist Type:Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy Regist Type:FSI_0002+testClass From the logging interceptor: "Invoke method Void Test():FSI_0002+testClass at 9:30:27" hello From the logging interceptor: "Method Void Test():FSI_0002+testClass returned at 9:30:27" val it : unit = ()
拦截成功。

下面略加改写原来的类定义。使接口都以virtural的情势暴露出来
type TenantStore() as x= //do printfn "new TenantStore %A" (x.GetHashCode()) abstract Msg : unit -> unit default x.Msg() = printfn "Hello, it's TenantStore" abstract Dispose : unit -> unit default x.Dispose() = printfn "TenantStore hase been cleaned" interface ITenantStore with member x.Msg() = x.Msg() interface IDisposable with member x.Dispose() = x.Dispose()
有些繁琐,接口实现的代码可以复用,不幸中的万幸。下面的例子中我同时测试1下多接口之间转换的情况,看看VirtualMethodInterceptor是不是也支持多接口,文档上没有明确表明。
测试代码
using(new UnityContainer())(fun ctner-> ctner.AddNewExtension<Interception>() |> ignore ctner.RegisterType<ITenantStore, TenantStore>(new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<LogingInterceptionBehavior>()) |> ignore ctner.RegisterType<testClass>(new Interceptor<VirtualMethodInterceptor>(), new InterceptionBehavior<LogingInterceptionBehavior>()) |> ignore showregistrations ctner let t = ctner.Resolve<ITenantStore>() t.Msg() let o = (box t) :?> IDisposable o.Dispose() )

TransparentProxyInterceptor
成功 结果
Regist Type:Microsoft.Practices.Unity.IUnityContainer Regist Type:Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy Regist Type:FSI_0002+ITenantStore From the logging interceptor: "Invoke method System.Type GetType():System.Object at 9:38:47" From the logging interceptor: "Method System.Type GetType():System.Object returned FSI_0010+TenantStore at 9:38:47" From the logging interceptor: "Invoke method Void Msg():FSI_0002+ITenantStore at 9:38:47" Hello, it's TenantStore From the logging interceptor: "Method Void Msg():FSI_0002+ITenantStore returned at 9:38:47" From the logging interceptor: "Invoke method System.Type GetType():System.Object at 9:38:47" From the logging interceptor: "Method System.Type GetType():System.Object returned FSI_0010+TenantStore at 9:38:47" From the logging interceptor: "Invoke method Void Dispose():System.IDisposable at 9:38:47" TenantStore hase been cleaned From the logging interceptor: "Method Void Dispose():System.IDisposable returned at 9:38:47" val it : unit = ()

InterfaceInterceptor
失败 结果:
Regist Type:Microsoft.Practices.Unity.IUnityContainer Regist Type:Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy Regist Type:FSI_0002+ITenantStore From the logging interceptor: "Invoke method Void Msg():FSI_0002+ITenantStore at 9:39:44" Hello, it's TenantStore From the logging interceptor: "Method Void Msg():FSI_0002+ITenantStore returned at 9:39:44" System.InvalidCastException: 没法将类型为“DynamicModule.ns.Wrapped_ITenantStore_67632c824c8e42bbad5925d203ac819b”的对象强迫转换为类型“System.IDisposable”。 在 FSI_0015.it@149⑺.Invoke(UnityContainer ctner) 位置 E:WorkHellfsharp-practiseEnterpriseLibraryUnityProgram.fs:行号 157 在 Microsoft.FSharp.Core.Operators.Using[T,TResult](T resource, FSharpFunc`2 action) 在 <StartupCode$FSI_0015>.$FSI_0015.main@() 已因出错而停止

VirtualMethodInterceptor
成功 结果
Regist Type:Microsoft.Practices.Unity.IUnityContainer Regist Type:Microsoft.Practices.Unity.InterceptionExtension.InjectionPolicy Regist Type:FSI_0002+ITenantStore Regist Type:FSI_0002+testClass From the logging interceptor: "Invoke method Void Msg():FSI_0017+TenantStore at 9:42:01" Hello, it's TenantStore From the logging interceptor: "Method Void Msg():FSI_0017+TenantStore returned at 9:42:01" From the logging interceptor: "Invoke method Void Dispose():FSI_0017+TenantStore at 9:42:01" TenantStore hase been cleaned From the logging interceptor: "Method Void Dispose():FSI_0017+TenantStore returned at 9:42:01" val it : unit = ()

通过结果可以看到TransparentProxyInterceptor在构建的进程中多了1些步骤,翻了1下帮助文档。说这个代理是使用 TransparentProxy/RealProxy infrastructure生成的。因此速度最慢。而另两个则是通过动态代码生成的(这是甚么?反射?)。


这里可以有个小的结论了,InterfaceInterceptor最小巧实用,其他两个或多或少在使用上都要留意1下各自的特性。
再看看可替换性。
(box t) :?> TenantStore
结果
TransparentInterceptor 失败
VirtualMethodInterceptor 成功
InterfaceInterceptor 失败   和料想的1致

以上
------分隔线----------------------------
------分隔线----------------------------

最新技术推荐