首页 > 代码库 > 通过fsharp 使用Enterprise Library Unity

通过fsharp 使用Enterprise Library Unity

<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">使用Ioc概念的Unity库的优点,简单的说就是进一步解耦系统各组件的依赖关系。客户端代码只需依赖需要使用的接口(服务)就可以快速的进行开发。</span>
1.基本流程,定义类-->配置container-->解析类,并使用-->析构(依策略)
2.注册的类型
注册实例,类似单件模式
注册类型,各种扩展
    构造函数类
        1.注册时InjectionConstructor声明类型,之前没有经过注册,无法解析;会在生成对象时产生错误。(可以在解析过程时化解)
let container = new UnityContainer()

type TenantStore() = 
    interface ITenantStore with
        member this.Msg() = printfn "Hello, it's TenantStore"
    interface IDisposable with
        member this.Dispose() = printfn "TenantStore hase been cleaned"

type ManagementController(st:ITenantStore, _name:string) =
    member this.TStore = st
    member val Name = _name with get, set
    interface IDisposable with
        member this.Dispose() = printfn "Control %A hase been cleaned" this.Name

using(new TenantStore())(fun x -> 
    (x:>ITenantStore).Msg())

container.RegisterType<ITenantStore, TenantStore>()
container.RegisterType<ManagementController>(new InjectionConstructor(typeof<ITenantStore>, typeof<string>))

using(container.Resolve<ManagementController>(new ParameterOverride("_name", (box "hello"))))(fun myctrl ->
    printfn "%A" myctrl.TStore)
        2.函数中的参数可以在解析过程中(Resolve的过程中)重载。
        3.泛型类注册,以参数形式表明注册类,可以在注册时忽略泛型类型,在解析时指定
    使用typeof获得类型时会默认用obj替换泛型类,无法产生延时定义的效果。需要改用typedefof来获取带泛型的类型
    [参考]http://stackoverflow.com/questions/6783284/how-to-get-generic-type-definition-for-crtp-type
type IMessage<'a> = 
    abstract member Send : 'a -> unit


type Message<'a>() = 
    interface IMessage<'a> with
        member this.Send(msg:'a) = 
            printfn "Send Message %A" msg

//Not work
//container.RegisterType(typeof<IMessage<_>>, typeof<Message<_>>)
container.RegisterType(typedefof<IMessage<_>>, typedefof<Message<_>>)

//观察注册类
container.Registrations |> Seq.iter (fun i -> printfn "Regist Type:%A" i.RegisteredType)

let y = container.Resolve<IMessage<int>>()                                              
y.Send(413)                                     

let z = container.Resolve<IMessage<bool>>()                                              
z.Send(true)     <span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">         </span>
4.属性注入
Fsharp的属性无法直接设为Null值,所以在进行属性注入的过程中需要用到一些技巧
如果是轻量级的对象可以默认给个对象实例做填充物,不过这肯定不是个好办法。
type MyClass() as x= 
    let t = new TenantStore() :> ITenantStore
    [<Dependency>]
    member val PProperty: ITenantStore = t with get, set
附加一个null field做填充物。这个实现最接近c#,不过接口多了的话,未整理的零零碎碎的小东西怎么也是桩心事。
type MyClass() as x= 
    [<DefaultValue>]
    val mutable t:ITenantStore
    [<Dependency>]
    member val PProperty: ITenantStore = x.t with get, set
其实null不是个好东西,异常之源!fsharp为了摆脱null给出了option的解决方案,这里能用么?我试了一下
type MyClass() as x= 
    [<Dependency>]
    member val PProperty: ITenantStore option = None with get, set
结果还真行!漂亮多了不是么?而且绝对没有null的参与。我觉得面向对象的哲学里,所有的对象都应该有一个确定的身份。null只是一个系统遗留产物,少用为好。不过这里也有个缺点。获得PProperty时需要获得背后的值,多了一步。

五种声明周期探索
默认为
0.短时生命周期(Transient LifeTime)
生成不一样的对象
container.RegisterType<ITenantStore, TenantStore>()

let a = container.Resolve<ITenantStore>()
let b = container.Resolve<ITenantStore>()
printfn "Is a eqaul to b: %A" (a.Equals(b))
</pre>false1.容器生命周期(Container LifetimeManger)近似于单件模式<pre name="code" class="plain">container.RegisterType<ITenantStore, TenantStore>(new ContainerControlledLifetimeManager())

let a = container.Resolve<ITenantStore>()
let b = container.Resolve<ITenantStore>()
printfn "Is a eqaul to b: %A" (a.Equals(b))

true
2.层次生命周期(Hierarchical Life Time)
脑补一个树形图
container.RegisterType<ITenantStore, TenantStore>(new HierarchicalLifetimeManager())
let childcontainer = container.CreateChildContainer()

let a = container.Resolve<ITenantStore>()
let b = childcontainer.Resolve<ITenantStore>()
printfn "Is a eqaul to b: %A" (a.Equals(b))

false
3单独解生命周期(PreResolve Life Time)
理解为当多个不同类依赖于同一个类时(资源类),获取该对象时并不会重复解析该类。
一定要为三层以上的对象结构,单层产生不了这样的效果
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"

type ManagementController(st:ITenantStore, _name:string) =
    member this.TStore = st
    member val Name = _name with get, set
    interface IDisposable with
        member this.Dispose() = printfn "Control %A hase been cleaned" this.Name

type ExManagementController(st:ITenantStore, _name:string) =
    member this.TStore = st
    member val Name = _name with get, set
    interface IDisposable with
        member this.Dispose() = printfn "Control %A hase been cleaned" this.Name

type CombineManagement(m1:ManagementController, m2:ExManagementController) = 
    member this.M1 = m1
    member this.M2 = m2

//注册
container.RegisterType<ITenantStore, TenantStore>(new PerResolveLifetimeManager())
container.RegisterType<ManagementController>(new InjectionConstructor(typeof<ITenantStore>, "xx"))
container.RegisterType<ExManagementController>(new InjectionConstructor(typeof<ITenantStore>, "yy"))
container.RegisterType<CombineManagement>()
//获取let o = container.Resolve<CombineManagement>()printfn "%d,%d" (o.M1.TStore.GetHashCode()) (o.M2.TStore.GetHashCode())

还有线程相关,网络相关,外部控制的生命周期,暂未深究

通过fsharp 使用Enterprise Library Unity