2013-01-18 70 views
0

我試圖在F#程序集中構建log4net樣式接口。關鍵屬性是公開一個返回對象實例的靜態方法。 log4net利用C#委託來完成任務,例如與LogManager.GetLogger("log123")。根據我的理解,代表們不如功能 - 作爲面向內部的F#庫的頭等艙。F#中的log4net樣式接口 - 靜態方法返回對象的實例

下面的簡化代碼完成了目標,但我不習慣使用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

可以在內部使用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) 

如果你不希望重載獲取功能,那麼你可以只使用一個模塊:

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 
相關問題