<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())
还有线程相关,网络相关,外部控制的生命周期,暂未深究