0

F# アセンブリで log4net スタイルのインターフェイスを構築しようとしています。key 属性は、オブジェクトのインスタンスを返す静的メソッドを公開しています。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

変更可能な値を保持するために参照セルを内部的に使用しても問題ありません。マップの代わりに.Net Dictionaryを使用することもできます。これは、 Mini IoC Containerを構築するときに取ったアプローチです。参照セルにアクセスする関数が複数のスレッドから呼び出されることが予想される場合は、おそらくロックまたは他のスレッド同期を使用する必要があります。

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
于 2013-02-11T07:56:10.693 に答える