F#中的log4net样式接口 - 静态方法返回对象的实例

时间:2013-01-18 04:35:26

标签: f# c#-to-f#

我正在尝试在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 

提前感谢您的评论。

1 个答案:

答案 0 :(得分:1)

可以在内部使用reference cell来保存可变值。您也可以使用.Net Dictionary代替地图。这是我在构建Mini IoC Container时采用的方法。如果您希望从多个线程调用访问引用单元格的函数,那么您应该使用lock或其他thread synchronization

有多种方法可以公开Get方法。如果您希望重载方法,那么您采用的静态成员方法很有用。在这种情况下,您可以考虑在单独的模块上使用static let作为静态本地:

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)

如果您不希望重载Get函数,那么您可以使用模块:

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