0

我正在尝试在 F# 程序集中构建 log4net 样式的界面。关键属性公开了一个返回对象实例的静态方法。log4net 使用 C# 委托来完成任务,例如使用LogManager.GetLogger("log123"). 据我了解,对于面向内向的 F# 库而言,与将函数作为第一类函数相比,代表不太受青睐。

下面的简化代码实现了目标,但我对使用 F# 引用单元格来保存实例化对象的映射感到不舒服。我对我的不适是否合理的反馈很感兴趣。

namespace Test
[<Interface>]
type IMyIface =
    abstract member Addi : int -> int
[<Sealed>]
type TheMainObject internal (x:int) = 
    let mutable sum = x
    interface IMyIface with
        member this.Addi(y:int) = sum <- sum + y; sum 
module internal Wrapr = 
    let mymap = ref Map.empty
    let mgr s = 
        let m = !mymap
        if Map.containsKey s m then m.[s] 
        else 
            let x = new TheMainObject(0)
            mymap := m.Add(s, x)
            x 
[<Sealed>]
type Mgr() = 
    static member Get(n:string) = 
        Wrapr.mgr n :> IMyIface

Program.fs 调用上面的库如下:

open Test
let a = Mgr.Get("hello")
printfn "%d" (a.Addi(1)) 
let c = Mgr.Get("hello")
printfn "%d, %A" (c.Addi(3)) (a = c) //prints 4, true 

提前感谢您的评论。

4

1 回答 1

1

It's OK to use a reference cell internally to hold a mutable value. You could also use a .Net Dictionary instead of a map. This is the approach I took while building a Mini IoC Container. If you expect the function accessing the reference cell to be called from multiple threads then you should probably use a lock or other thread synchronization.

There are a number of ways of exposing the Get method. The static member approach you have taken is useful if you expect to overload the method. In which case you may consider using static let for static locals over a separate module:

type [<Sealed>] Mgr() =     
    static let sync = obj()
    static let lookup = Dictionary()
    static let obtain name =
        match lookup.TryGetValue(name) with
        | true, x -> x
        | false,_ ->        
            let x = TheMainObject(0)
            lookup.Add(name,x)
            x
    static member Get(name:string) = 
        lock sync (fun () -> obtain name :> IMyIface)

If you do not expect to overload the Get function then you could just use a module:

module Mgr =
    let private lookup = ref Map.empty
    let private obtain name =
        match (!lookup).TryFind name with
        | Some(x) -> x
        | None ->        
            let x = TheMainObject(0)
            lookup := (!lookup).Add(name,x)
            x
    let Get name = obtain name :> IMyIface
于 2013-02-11T07:56:10.693 回答