简明地创建一个词典< _,obj>

时间:2011-09-13 20:14:18

标签: f#

是否有更短的方法来创建IDictionary<_,obj>,可能没有装箱每个值?这就是我所拥有的。

let values =
  [ "a", box 1
    "b", box "foo"
    "c", box true ]
  |> dict

Dictionary<_,obj>.Add可以在没有拳击的情况下调用,但是我无法找到一种比我更短的方法来使用它。

我希望除了定义一个拳击操作员之外的东西。

修改

根据Brian的建议,这是一种方法,但它有自己的问题。

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

7 个答案:

答案 0 :(得分:10)

这是一个解决方案,遵循kvb的建议(可能是最简洁,最清晰,到目前为止):

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

let values =
  [ "a" => 1
    "b" => "foo"
    "c" => true ]
  |> dict

答案 1 :(得分:3)

这是我能够掀起的最简单的事情。它有比拳击版更多的角色,但可能感觉不那么脏。请注意,^是右关联的(它是从ocaml继承的字符串连接运算符),它使其像::一样工作,并且它具有比,更强的优先级,这就是为什么在元组周围需要括号。

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

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

答案 2 :(得分:2)

我在FsSql中遇到了类似的问题,我只是在一个函数中隐藏拳击:

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

答案 3 :(得分:2)

这是另一个“解决方案”,它受到Brian的建议的启发,但它使用反射,因此有时间和安全成本。

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

答案 4 :(得分:1)

斯蒂芬的想法的变化:

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
)

答案 5 :(得分:0)

另一种解决方案,只需在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

当然values这里的不可变,就像你的问题一样,但我相信你可以在这个目标中采用相同的策略。

答案 6 :(得分:-1)

let v : (string*obj) list = [...]
let values = dict v

单向,列表文字左侧的类型签名将自动向上转换每个元素。