3 people like it.

.NET 1.1 collections in F#

Even with the latest tools, we're sometimes exposed to .NET archeaology: parts of the framework designed before .NET 2. Examples of this are the dictionary classes from System.Collections, which are a little strongly typed, but not quite -- you see them if you call HttpUtility.ParseQueryString, or if you use pretty much anything in System.Configuration. Here's some code to make these classes a little safer in F#.

 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: 
29: 
30: 
31: 
32: 
33: 
34: 
35: 
open System.Collections

let inline pairs (collection : ^c when ^c :> IEnumerable and ^c : (member get_Item : 'a -> 'b)) : seq<'a * 'b> =
    seq {
        match collection.GetEnumerator() with
        | :? IDictionaryEnumerator as en ->
            while en.MoveNext() do
                yield unbox en.Key, unbox en.Value

        | en ->
            while en.MoveNext() do
                let key = unbox en.Current
                let value = (^c : (member get_Item : 'a -> 'b) (collection, key))
                yield key, value
    }


#r "System.Web"
open System.Collections.Specialized
open System.Web

for key, value in pairs (HttpUtility.ParseQueryString("hello=world&hello=tim&fsharp=cool")) do
    printfn "%s = %s" key value

let ht = Hashtable()
ht.["hello"] <- "world"
ht.["fsharp"] <- "cool"
for key, value in pairs ht do
    printfn "%s = %s" (unbox key) (unbox value)

let nvc = NameValueCollection()
nvc.["hello"] <- "world"
nvc.["fsharp"] <- "cool"
for key, value in pairs nvc do
    printfn "%s = %s" key value
namespace System
namespace System.Collections
val pairs : collection:'c -> seq<'a * 'b> (requires 'c :> IEnumerable and member get_Item)

Full name: Script.pairs
val collection : 'c (requires 'c :> IEnumerable and member get_Item)
type IEnumerable =
  member GetEnumerator : unit -> IEnumerator

Full name: System.Collections.IEnumerable
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

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

--------------------
type seq<'T> = Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
IEnumerable.GetEnumerator() : IEnumerator
type IDictionaryEnumerator =
  member Entry : DictionaryEntry
  member Key : obj
  member Value : obj

Full name: System.Collections.IDictionaryEnumerator
val en : IDictionaryEnumerator
IEnumerator.MoveNext() : bool
val unbox : value:obj -> 'T

Full name: Microsoft.FSharp.Core.Operators.unbox
property IDictionaryEnumerator.Key: obj
property IDictionaryEnumerator.Value: obj
val en : IEnumerator
val key : 'a
property IEnumerator.Current: obj
val value : 'b
namespace System.Collections.Specialized
namespace System.Web
val key : string
val value : string
Multiple items
type HttpUtility =
  new : unit -> HttpUtility
  static member HtmlAttributeEncode : s:string -> string + 1 overload
  static member HtmlDecode : s:string -> string + 1 overload
  static member HtmlEncode : s:string -> string + 2 overloads
  static member JavaScriptStringEncode : value:string -> string + 1 overload
  static member ParseQueryString : query:string -> NameValueCollection + 1 overload
  static member UrlDecode : str:string -> string + 3 overloads
  static member UrlDecodeToBytes : str:string -> byte[] + 3 overloads
  static member UrlEncode : str:string -> string + 3 overloads
  static member UrlEncodeToBytes : str:string -> byte[] + 3 overloads
  ...

Full name: System.Web.HttpUtility

--------------------
HttpUtility() : unit
HttpUtility.ParseQueryString(query: string) : NameValueCollection
HttpUtility.ParseQueryString(query: string, encoding: System.Text.Encoding) : NameValueCollection
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val ht : Hashtable

Full name: Script.ht
Multiple items
type Hashtable =
  new : unit -> Hashtable + 14 overloads
  member Add : key:obj * value:obj -> unit
  member Clear : unit -> unit
  member Clone : unit -> obj
  member Contains : key:obj -> bool
  member ContainsKey : key:obj -> bool
  member ContainsValue : value:obj -> bool
  member CopyTo : array:Array * arrayIndex:int -> unit
  member Count : int
  member GetEnumerator : unit -> IDictionaryEnumerator
  ...

Full name: System.Collections.Hashtable

--------------------
Hashtable() : unit
Hashtable(capacity: int) : unit
Hashtable(equalityComparer: IEqualityComparer) : unit
Hashtable(d: IDictionary) : unit
Hashtable(capacity: int, loadFactor: float32) : unit
Hashtable(capacity: int, equalityComparer: IEqualityComparer) : unit
Hashtable(d: IDictionary, loadFactor: float32) : unit
Hashtable(d: IDictionary, equalityComparer: IEqualityComparer) : unit
Hashtable(capacity: int, loadFactor: float32, equalityComparer: IEqualityComparer) : unit
Hashtable(d: IDictionary, loadFactor: float32, equalityComparer: IEqualityComparer) : unit
val key : obj
val value : obj
val nvc : NameValueCollection

Full name: Script.nvc
Multiple items
type NameValueCollection =
  inherit NameObjectCollectionBase
  new : unit -> NameValueCollection + 7 overloads
  member Add : c:NameValueCollection -> unit + 1 overload
  member AllKeys : string[]
  member Clear : unit -> unit
  member CopyTo : dest:Array * index:int -> unit
  member Get : name:string -> string + 1 overload
  member GetKey : index:int -> string
  member GetValues : name:string -> string[] + 1 overload
  member HasKeys : unit -> bool
  member Item : string -> string with get, set
  ...

Full name: System.Collections.Specialized.NameValueCollection

--------------------
NameValueCollection() : unit
NameValueCollection(col: NameValueCollection) : unit
NameValueCollection(capacity: int) : unit
NameValueCollection(equalityComparer: IEqualityComparer) : unit
NameValueCollection(capacity: int, equalityComparer: IEqualityComparer) : unit
NameValueCollection(capacity: int, col: NameValueCollection) : unit
Raw view Test code New version

More information

Link:http://fssnip.net/iE
Posted:10 years ago
Author:Tim Robinson
Tags: generics , inline , retro