2010-04-27 19 views
7

implementieren So, da dann folgenden CodeWie kann ich das gleiche Verhalten wie Dictionary.TryGetValue

type MyClass() = 
    let items = Dictionary<string,int>() 
    do 
    items.Add ("one",1) 
    items.Add ("two",2) 
    items.Add ("three",3) 
    member this.TryGetValue (key,value) = 
    items.TrygetValue (key,value) 
let c = MyClass() 

let d = Dictionary<string,int>() 
d.Add ("one",1) 
d.Add ("two",2) 
d.Add ("three",3) 

und den folgenden Testcode

let r1,v1 = d.TryGetValue "one" 
let r2,v2 = c.TryGetValue "one" 

Die r1, arbeitet v1 Linie in Ordnung. Die r2, v2 Linienbomben; beschweren c.TryGetValue muss ein Tupel gegeben werden. Interessanterweise ist die Signatur von TryGetValue in jeder Zeile anders. Wie kann ich erreichen, dass meine benutzerdefinierte Implementierung dasselbe Verhalten wie die BCL-Version aufweist? Oder anders gefragt, da F # (implizit) das Konzept von Tuple-Parametern, Curry-Parametern und BCL-Parametern hat und ich zwischen Curry- und Tupel-Stil unterscheiden kann, wie kann ich den dritten Stil erzwingen (a la BCL-Methoden))

Lassen Sie mich wissen, wenn dies unklar ist.

Antwort

8

TryGetValue hat einen out-Parameter, so müssen Sie das gleiche in F # tun (über ein byref mit OutAttribute markiert):

open System.Runtime.InteropServices 
type MyDict<'K,'V when 'K : equality>() = // ' 
    let d = new System.Collections.Generic.Dictionary<'K,'V>() 
    member this.TryGetValue(k : 'K, [<Out>] v: byref<'V>) = 
     let ok, r = d.TryGetValue(k) 
     if ok then 
      v <- r 
     ok    

let d = new MyDict<string,int>() 
let ok, i = d.TryGetValue("hi") 
let mutable j = 0 
let ok2 = d.TryGetValue("hi", &j) 

F # automagically können Sie Suffix drehen Parameter in den Rückgabewert aus, so dass Sie nur müssen eine Methode erstellen, die mit einem out-Parameter endet.

+0

Dank. Ich habe das tatsächlich ausprobiert, wusste aber nicht, dass ich das OutAttribute brauche. Ich nahm an, die Byref <'v> wäre genug. – pblasucci

+0

byref selbst ist wie 'ref' in C# (im Gegensatz zu C# 'out'). – Brian

+2

ah, ja: ref, out ... gib mir einfach Tupel jeden Tag! – pblasucci

4

Persönlich habe ich nie die bool TryXXX(stringToParseOrKeyToLookup, out parsedInputOrLookupValue_DefaultIfParseFailsOrLookupNotFound) Muster im BCL verwendet gemocht. Und während der F # Trick, ein Tupel zurückzugeben, nett ist, brauche ich selten, wenn überhaupt, den Standardwert, wenn eine Syntaxanalyse oder eine Suche fehlschlägt. Tatsächlich würden die Some/None Muster perfekt sein (wie Seq.tryFind):

type MyClass() = 
    let items = System.Collections.Generic.Dictionary<string,int>() 
    do 
    items.Add ("one",1) 
    items.Add ("two",2) 
    items.Add ("three",3) 
    member this.TryGetValue (key) = 
    match items.TryGetValue(key) with 
     | (true, v) -> Some(v) 
     | _ -> None 

let c = MyClass() 

let printKeyValue key = 
    match c.TryGetValue(key) with 
    | Some(value) -> printfn "key=%s, value=%i" key value 
    | None -> printfn "key=%s, value=None" key 

//> printKeyValue "three";; 
//key=three, value=3 
//val it : unit =() 
//> printKeyValue "four";; 
//key=four, value=None 
//val it : unit =() 
+0

Verwenden Sie "Match mit" hier, um das Tupel zu entsprechen, ist pure Poesie. Benutzte diesen Ansatz in meinem Code, sehr nett! Vielen Dank! – gjvdkamp