【问题标题】:Cast/Conversion Problem投射/转换问题
【发布时间】:2011-04-12 23:03:09
【问题描述】:

在下面的 sn-p 中,我试图提取包含在嵌套元组中的 recid,该元组形成一个 dict 键。 嵌套元组格式为 (Int32, (boolean, boolean)) -

我正在寻找 Int32 项的值(即 实际上是 db 记录的行 ID)。

在下面的匹配代码中,我尝试将 recid 添加到列表中,但首先我将对象转换为整数。
但是,这会产生以下错误 - 不知道为什么?

错误: 此运行时强制或类型测试从类型 'a 到 int32
涉及基于此程序点之前的信息的不确定类型。 某些类型不允许运行时类型测试。需要进一步的类型注释。 此处引用的字典定义为:

// Create Dict  
let rdict =  new Dictionary<_,_>()
// Add elements
rdict.Add( (x.["PatientID"],(true,true) ),ldiff) 

// Extract Dict items 
let reclist = new ResizeArray<int32>()
for KeyValue(k,v) in rdict do
match k with
    | ((recid,(true,true)) ->
     printfn "Found a matching Record: %A " recid;   // <- prints correct result
     let n = (recid:?> int32)                            // <- coercion error
         reclist.Add(n)

【问题讨论】:

  • rdict.Add( (x.["PatientID"],(true,true) ) 行的左括号和右括号的数量不匹配。 Dictionary 的键和值类型是什么? int*(bool*bool) 是否仅用作键类型,或者int 是键类型而bool*bool 是值类型?另外,x.["PatientID"] 的实际类型是什么?这会返回一个int 还是一个装箱的int(即obj,可以转换为int)?
  • 糟糕 - 我在发布 rdict.add 行时搞砸了 - 现在已更正。 (我实际上/正在构建一个行/列对列表作为dict值。dict键实际上是一个复合(rid,(boolean,boolean))值。(布尔值定义rec是否存在于一对表中). x.["PatientID"] 是从 db 表中检索到的(未装箱的)int 值。
  • 实际上,还有一个问题——如果伴随的bool 对是true, true 而不是任何其他组合,您是否打算只将rdict 中的ID 复制到reclist? /跨度>
  • @ildjarn:我在这里比较 2 个 db 表,所以对于报告摘要,我希望选择为几个不同的匹配条件(例如,相交计数;a 不在 b 计数中;b 不计数)。顺便说一句,我认为装箱和拆箱值可能会起作用(不确定为什么当 printfn 正确处理 cvn 时需要这样做) - 我需要进一步测试它。
  • printfn 正确处理recid 因为您使用%A 作为格式说明符,它适用于任何类型;我怀疑如果您使用%d 作为格式说明符,它会失败,这意味着x.["PatientID"] 实际上返回int。假设您使用的是 Visual Studio,您不能将鼠标悬停在 rdict 上并查看工具提示中的类型吗?

标签: f# dictionary casting match tuples


【解决方案1】:

假设rdictDictionary&lt;int*(bool*bool), _&gt; 然后生成ResizeArray&lt;int&gt; 我建议:

let reclist =
    (ResizeArray<_>(), rdict.Keys)
    ||> Seq.fold(fun list (id,_) -> list.Add id; list)

另外,Dictionary&lt;int*(bool*bool), _&gt; 让我觉得很奇怪。为什么不Dictionary&lt;int*bool*bool, _&gt;?即,为什么要将 bool 对嵌套为第二个元组?如果您进行此更改,那么人们会这样称呼rdict.Add

rdict.Add ((x.["PatientID"], true, true), ldiff)

reclist 将改为:

let reclist =
    (ResizeArray<_>(), rdict.Keys)
    ||> Seq.fold(fun list (id,_,_) -> list.Add id; list)

编辑:在您的评论中,您提到希望基于Dictionary 键中两个bools 的不同组合构建单独的ResizeArrays。这是这样做的一个想法:

let reclistOnlyA, reclistOnlyB, reclistBoth, reclistNeither =
    ((ResizeArray<_>(), ResizeArray<_>(), ResizeArray<_>(), ResizeArray<_>()), rdict.Keys)
    ||> Seq.fold(fun (a, b, both, neither as lists) (id, bools) ->
        (match bools with
         | true, false  -> a
         | false, true  -> b
         | true, true   -> both
         | false, false -> neither).Add id
        lists)

【讨论】:

  • dict 键是从最初的版本演变而来的,只有 recid 作为值。从逻辑上讲,我对布尔值的看法与 reci 有所不同,所以我认为我将它们放在一个单独的嵌套元组中。我可以看到您的方法有一些优势 - 到目前为止,感谢您的帮助。
  • @BrendanC:效率(减少分配计数)是int*bool*bool 相对于int*(bool*bool) 的唯一真正优势。从风格上讲,你所拥有的东西让我觉得很奇怪,但如果它对你有意义,我认为它没有任何重大伤害。 :-]
【解决方案2】:

为了完整性和未来参考,我只想发布基于进一步测试的结果。 通过装箱/拆箱,我能够成功修改我之前发布的代码。

希望这对将来的其他人有所帮助。

    // Add initial value note the box call here
diff_dict.Add( (box x.["PatientID"],(true,true) ),ldiff) 


let reclist = new ResizeArray<int32>()
for KeyValue(k,v) in rdict do
    //printfn "Difference Dictionary - Key: %A; Value: %A; " k v 
    match k with
        // extract the result - note the 'unbox' call
        | (recid,(true,false)) ->  let n:int32 = unbox recid
                                   reclist.Add(n) 

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-14
    • 2014-05-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多