通過fsharp 使用Enterprise Library Unity 3 - 三種攔截模式的探索
阿新 • • 發佈:2017-05-07
clean stc ane adding clas 是什麽 idc 內部函數 ash
這篇就三種攔截模式進行一下探索。
回顧一下類的聲明。兩個接口,一個實現。
以下進行一些測試。
showregistrations 顯示已註冊的類型。用來展示註冊內部的信息。另外,在交互式代碼中使用using相較於use更為的合適,FSI聲明的對象的生命周期是全局的,在做試驗的時候無法控制container。重復清環境不太方便。
InterfaceInterceptor的結果
攔截失敗。 研究後發覺是由於Fsharp中並不直接支持Virtual方法,Fsharp實現接口成員,默覺得顯示(explicit)實現,想要申明Virtual方法須要一些技巧。
可參考http://cs.hubfs.net/topic/None/73936
再定義一個測試類來試試VirtualMethodInterceptor。
結果
以下稍加改寫原來的類定義。使接口都以virtural的形式暴露出來
TransparentProxyInterceptor
成功 結果
InterfaceInterceptor
失敗 結果:
VirtualMethodInterceptor
成功 結果
通過結果能夠看到TransparentProxyInterceptor在構建的過程中多了一些步驟。翻了一下幫助文檔。說這個代理是使用 TransparentProxy/RealProxy infrastructure生成的。因而速度最慢。
TransparentInterceptor 失敗
VirtualMethodInterceptor 成功
InterfaceInterceptor 失敗 和料想的一致
以上
特性總結
類型 | 特點 | 其它 | |
InterfaceInterceptor | Innstance | 僅單接口 | 類內部函數互相引用無法引起攔截行為 |
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”。 在 [email protected](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 失敗 和料想的一致
以上
通過fsharp 使用Enterprise Library Unity 3 - 三種攔截模式的探索