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

这篇就三种拦截模式进行一下探索。
                                      

特性总结

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


回忆一下类的声明,两个接口,一个实现。fsharp实现接口函数的方法与csharp并不完全一致,会造成一些实现上的困扰,这在后面会提到。
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"

下面进行一些测试。
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方法需要一些技巧。
可参考 http://cs.hubfs.net/topic/None/73936


再定义一个测试类来试试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()
有些繁琐,接口实现的代码可以复用,不幸中的万幸。下面的例子中我同时测试一下多接口之间转换的情况,看看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-7.Invoke(UnityContainer ctner) 位置 E:\WorkHell\fsharp-practise\EnterpriseLibraryUnity\Program.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在构建的过程中多了一些步骤,翻了一下帮助文档。说这个代理是使用 TransparentProxy/RealProxy infrastructure生成的。因而速度最慢。而另两个则是通过动态代码生成的(这是什么?反射?)。


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

以上
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值