问题描述:

### EDIT

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.

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.