2016-06-30 5 views
4

Wenn ich versuche, IDictionary mit dem folgenden CodeF # Generisches IDictionary Erweiterung fehlgeschlagen

type Generic.IDictionary<'TKey, 'TValue> with 
    member this.GetOrAdd (key:'TKey, fun':'TKey -> 'TValue) = 
     match this.ContainsKey(key) with 
     | true -> this.Item(key) 
     | false -> 
      let val_ = fun' key 
      this.Add(key, val_) 
      val_ 

let dd = dict[(1,2); (3,4)] 
let f = fun x -> 2*x 
let d5 = dd.GetOrAdd(5, f) 

Ich habe die folgenden Fehler in der Laufzeit zu verlängern.

System.NotSupportedException: Ausnahme vom Typ> 'System.NotSupportedException' wurde ausgelöst. bei [email protected]stem-> Collections-Generic-IDictionary 2-Add(TKey key, T value) at FSI_0011.IDictionary 2.GetOrAdd [TKey, TValue] (IDictionary 2 this, >TKey key, FSharpFunc 2 Spaß ') in> D: \ BaiduYunDownload \ DroiEtl \ Droi.MyToPG \ Util.Sync.fs. Linie 259 bei $ FSI_0018.main @() in> D: \ BaiduYunDownload \ DroiEtl \ Droi.MyToPG \ Util.Sync.fs: Linie 264 aufgrund Gestoppt

auf Fehler

Aber der Compiler beschwert sich nicht beim Bau ... Bitte helfen Sie mir ...

+1

Es wäre etwas schneller, 'TryGetValue' anstelle von' ContainsKey' zu verwenden, da der "bereits existierende" Codepfad nur eine Wörterbuchsuche anstelle der zwei Suchvorgänge, die Sie gerade machen, durchführen müsste. –

Antwort

8

dictis documented einen read-only zurückzukehrenIDictionary<_,_> - Sie rufen dann .Add darauf, und die Backing-Klasse wirft zu Recht eine Ausnahme.

eine echte Dictionary Instanz statt und Sie werden sehen, es funktioniert wie erwartet:

open System.Collections.Generic 

type IDictionary<'TKey, 'TValue> with 
    member this.GetOrAdd (key:'TKey, fun':'TKey -> 'TValue) = 
     match this.ContainsKey key with 
      | true -> this.Item key 
      | false -> let val' = fun' key 
        this.Add (key, val') 
        val' 

let dd = 
    let d = Dictionary() 
    d.Add (1, 2) 
    d.Add (3, 4) 
    d 

printfn "%A" dd 
dd.GetOrAdd (5, (fun x -> 2 * x)) |> printfn "%A :: %d" dd 
dd.GetOrAdd (5, (fun x -> 9 * x)) |> printfn "%A :: %d" dd 

Ausgang:

seq [[1, 2]; [3, 4]] 
seq [[1, 2]; [3, 4]; [5, 10]] :: 10 
seq [[1, 2]; [3, 4]; [5, 10]] :: 10 

Online Demo

Implementierung weisen, @ JoelMueller Vorschlag ist eine offensichtliche Verbesserung:

type IDictionary<'TKey, 'TValue> with 
    member this.GetOrAdd (key:'TKey, fun':'TKey -> 'TValue) = 
     match this.TryGetValue key with 
      | true, val' -> val' 
      | false, _ -> let val' = fun' key 
          this.Add (key, val') 
          val'