4 people like it.

Dictionary with comparer as type parameter

Tired of confusing dictionary instances with different comparers (I am)? Stick it in the type, à la ocaml-core maps.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
22: 
23: 
24: 
25: 
26: 
27: 
28: 
open System
open System.Collections.Generic

type Dictionary<'TKey, 'TValue, 'TComparer when 'TKey : equality and 'TComparer :> IEqualityComparer<'TKey>>(comparer: 'TComparer) =
    inherit Dictionary<'TKey, 'TValue>(comparer)

type DelegatingEqualityComparer<'a>(comparer: IEqualityComparer<'a>) = 
    interface IEqualityComparer<'a> with
        member x.Equals(a,b) = comparer.Equals(a,b)
        member x.GetHashCode a = comparer.GetHashCode a

type StringComparerInvariantCultureIgnoreCase() =
    inherit DelegatingEqualityComparer<string>(StringComparer.InvariantCultureIgnoreCase)

type StringComparerInvariantCulture() =
    inherit DelegatingEqualityComparer<string>(StringComparer.InvariantCulture)

let doSomething (data: Dictionary<string, _, StringComparerInvariantCultureIgnoreCase>) =
    printfn "%A" data.["one"]
    printfn "%A" data.["two"]

let data = Dictionary<_,int,_>(StringComparerInvariantCulture())
data.["One"] <- 1
data.["Two"] <- 2
doSomething data // doesn't compile, as the comparers are different!
let data2 = Dictionary<_,int,_>(StringComparerInvariantCultureIgnoreCase())
for KeyValue(k,v) in data do data2.Add(k,v)
doSomething data2 // works as expected
namespace System
namespace System.Collections
namespace System.Collections.Generic
Multiple items
type Dictionary<'TKey,'TValue> =
  new : unit -> Dictionary<'TKey, 'TValue> + 5 overloads
  member Add : key:'TKey * value:'TValue -> unit
  member Clear : unit -> unit
  member Comparer : IEqualityComparer<'TKey>
  member ContainsKey : key:'TKey -> bool
  member ContainsValue : value:'TValue -> bool
  member Count : int
  member GetEnumerator : unit -> Enumerator<'TKey, 'TValue>
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Item : 'TKey -> 'TValue with get, set
  ...
  nested type Enumerator
  nested type KeyCollection
  nested type ValueCollection

Full name: System.Collections.Generic.Dictionary<_,_>

--------------------
type Dictionary<'TKey,'TValue,'TComparer (requires equality and 'TComparer :> IEqualityComparer<'TKey>)> =
  inherit Dictionary<'TKey,'TValue>
  new : comparer:'TComparer -> Dictionary<'TKey,'TValue,'TComparer>

Full name: Script.Dictionary<_,_,_>

--------------------
Dictionary() : unit
Dictionary(capacity: int) : unit
Dictionary(comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>) : unit
Dictionary(capacity: int, comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>, comparer: IEqualityComparer<'TKey>) : unit
Dictionary(info: Runtime.Serialization.SerializationInfo, context: Runtime.Serialization.StreamingContext) : unit

--------------------
new : comparer:'TComparer -> Dictionary<'TKey,'TValue,'TComparer>
type IEqualityComparer<'T> =
  member Equals : x:'T * y:'T -> bool
  member GetHashCode : obj:'T -> int

Full name: System.Collections.Generic.IEqualityComparer<_>
val comparer : #IEqualityComparer<'TKey> (requires equality)
Multiple items
type DelegatingEqualityComparer<'a> =
  interface IEqualityComparer<'a>
  new : comparer:IEqualityComparer<'a> -> DelegatingEqualityComparer<'a>

Full name: Script.DelegatingEqualityComparer<_>

--------------------
new : comparer:IEqualityComparer<'a> -> DelegatingEqualityComparer<'a>
val comparer : IEqualityComparer<'a>
val x : DelegatingEqualityComparer<'a>
override DelegatingEqualityComparer.Equals : a:'a * b:'a -> bool

Full name: Script.DelegatingEqualityComparer`1.Equals
val a : 'a
val b : 'a
Object.Equals(obj: obj) : bool
IEqualityComparer.Equals(x: 'a, y: 'a) : bool
override DelegatingEqualityComparer.GetHashCode : a:'a -> int

Full name: Script.DelegatingEqualityComparer`1.GetHashCode
Object.GetHashCode() : int
IEqualityComparer.GetHashCode(obj: 'a) : int
Multiple items
type StringComparerInvariantCultureIgnoreCase =
  inherit DelegatingEqualityComparer<string>
  new : unit -> StringComparerInvariantCultureIgnoreCase

Full name: Script.StringComparerInvariantCultureIgnoreCase

--------------------
new : unit -> StringComparerInvariantCultureIgnoreCase
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = String

Full name: Microsoft.FSharp.Core.string
type StringComparer =
  member Compare : x:obj * y:obj -> int + 1 overload
  member Equals : x:obj * y:obj -> bool + 1 overload
  member GetHashCode : obj:obj -> int + 1 overload
  static member Create : culture:CultureInfo * ignoreCase:bool -> StringComparer
  static member CurrentCulture : StringComparer
  static member CurrentCultureIgnoreCase : StringComparer
  static member InvariantCulture : StringComparer
  static member InvariantCultureIgnoreCase : StringComparer
  static member Ordinal : StringComparer
  static member OrdinalIgnoreCase : StringComparer

Full name: System.StringComparer
property StringComparer.InvariantCultureIgnoreCase: StringComparer
Multiple items
type StringComparerInvariantCulture =
  inherit DelegatingEqualityComparer<string>
  new : unit -> StringComparerInvariantCulture

Full name: Script.StringComparerInvariantCulture

--------------------
new : unit -> StringComparerInvariantCulture
property StringComparer.InvariantCulture: StringComparer
val doSomething : data:Dictionary<string,'a,StringComparerInvariantCultureIgnoreCase> -> unit

Full name: Script.doSomething
val data : Dictionary<string,'a,StringComparerInvariantCultureIgnoreCase>
Multiple items
type Dictionary<'TKey,'TValue> =
  new : unit -> Dictionary<'TKey, 'TValue> + 5 overloads
  member Add : key:'TKey * value:'TValue -> unit
  member Clear : unit -> unit
  member Comparer : IEqualityComparer<'TKey>
  member ContainsKey : key:'TKey -> bool
  member ContainsValue : value:'TValue -> bool
  member Count : int
  member GetEnumerator : unit -> Enumerator<'TKey, 'TValue>
  member GetObjectData : info:SerializationInfo * context:StreamingContext -> unit
  member Item : 'TKey -> 'TValue with get, set
  ...
  nested type Enumerator
  nested type KeyCollection
  nested type ValueCollection

Full name: System.Collections.Generic.Dictionary<_,_>

--------------------
type Dictionary<'TKey,'TValue,'TComparer (requires equality and 'TComparer :> IEqualityComparer<'TKey>)> =
  inherit Dictionary<'TKey,'TValue>
  new : comparer:'TComparer -> Dictionary<'TKey,'TValue,'TComparer>

Full name: Script.Dictionary<_,_,_>

--------------------
Dictionary() : unit
Dictionary(capacity: int) : unit
Dictionary(comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>) : unit
Dictionary(capacity: int, comparer: IEqualityComparer<'TKey>) : unit
Dictionary(dictionary: IDictionary<'TKey,'TValue>, comparer: IEqualityComparer<'TKey>) : unit

--------------------
new : comparer:'TComparer -> Dictionary<'TKey,'TValue,'TComparer>
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val data : Dictionary<string,int,StringComparerInvariantCulture>

Full name: Script.data
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val data2 : Dictionary<string,int,StringComparerInvariantCultureIgnoreCase>

Full name: Script.data2
active recognizer KeyValue: KeyValuePair<'Key,'Value> -> 'Key * 'Value

Full name: Microsoft.FSharp.Core.Operators.( |KeyValue| )
val k : string
val v : int
Dictionary.Add(key: string, value: int) : unit
Raw view Test code New version

More information

Link:http://fssnip.net/lZ
Posted:10 years ago
Author:Mauricio Scheffer
Tags: types , dictionary