当前位置: 动力学知识库 > 问答 > 编程问答 >

f# - Concisely creating an IDictionary<_,obj>

问题描述:

Is there a shorter way of creating an IDictionary<_,obj>, possibly without boxing every value? This is what I have.

let values =

[ "a", box 1

"b", box "foo"

"c", box true ]

|> dict

Dictionary<_,obj>.Add can be called without boxing, but I couldn't figure out a way to use it that's shorter than what I have.

I'm hoping for something other than defining a boxing operator.

EDIT

Based on Brian's suggestion, here's one way to do it, but it has its own problems.

let values =

Seq.zip ["a"; "b"; "c"] ([1; "foo"; true] : obj list) |> dict

网友答案:

Here's a solution, following kvb's suggestion (probably the most concise, and clearest, so far):

let inline (=>) a b = a, box b

let values =
  [ "a" => 1
    "b" => "foo"
    "c" => true ]
  |> dict
网友答案:

Here's the slickest thing I was able to whip up. It has more characters than your boxing version, but possibly feels a little less dirty. Note that the ^ is right-associative (it's the string concat operator inherited from ocaml), which lets it work like ::, and it has stronger precedence than ,, which is why the parenthesis are needed around the tuples.

let inline (^+) (x1:'a,x2:'b) (xl:('a*obj) list) = 
    (x1,box x2)::xl

let values =
  ("a", 1) ^+  ("b", "foo") ^+ ("c", true) ^+ []
  |> dict
网友答案:

Here's another "solution" which is inspired from Brian's suggestion but it uses reflection so there is a time and safety cost.

let unboxPair (pair:obj) =
    let ty = pair.GetType()
    let x = ty.GetProperty("Item1").GetValue(pair,null) :?> string
    let y = ty.GetProperty("Item2").GetValue(pair,null)
    x,y

let unboxPairs (pairs:obj list) =
  pairs |> List.map unboxPair  

let values =
  unboxPairs
    ["a", 1
     "b", "foo"
     "c", true]
  |> dict
网友答案:

I had a similar problem in FsSql and I just tucked away boxing in a function:

let inline T (a,b) = a, box b
let values = dict [T("a",1); T("b","foo"); T("c",true)]
网友答案:

A variation of Stephen's idea:

open System
open System.Collections.Generic

type Dictionary<'a,'b> with
  member this.Add([<ParamArray>] args:obj[]) =
    match args.Length with
    | n when n % 2 = 0 ->
      for i in 1..2..(n-1) do
        this.Add(unbox args.[i-1], unbox args.[i])
    | _ -> invalidArg "args" "even number of elements required"

let d = Dictionary<string,obj>()
d.Add(
  "a", 1,
  "b", "foo",
  "c", true
)
网友答案:
let v : (string*obj) list = [...]
let values = dict v

Is one way, the type signature on the left of the list literal will auto-upcast each element.

网友答案:

Yet another solution, simply define a bunch of overloaded extension members on Dictionary<'a,'b>:

open System.Collections.Generic
type Dictionary<'a,'b> with
    member this.Add(x1,y1,x2,y2) =
        this.Add(x1,y1)
        this.Add(x2,y2)
    member this.Add(x1,y1,x2,y2,x3,y3) =
        this.Add(x1,y1,x2,y2)
        this.Add(x3,y3)
    member this.Add(x1,y1,x2,y2,x3,y3,x4,y4) =
        this.Add(x1,y1,x2,y2,x3,y3)
        this.Add(x4,y4)
    member this.Add(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5) =
        this.Add(x1,y1,x2,y2,x3,y3,x4,y4)
        this.Add(x5,y5)
    member this.Add(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5,x6,y6) =
        this.Add(x1,y1,x2,y2,x3,y3,x4,y4,x5,y5)
        this.Add(x6,y6)
    //etc.

let values = 
    let d = Dictionary<_,obj>()
    d.Add("a", 1, 
          "b", "foo", 
          "c", true)
    d

Of course values here is not immutable like in your question, but I'm sure you could employ the same strategy in that goal.

分享给朋友:
您可能感兴趣的文章:
随机阅读: