为什么不是IDictionary< _,>键与派生类型兼容?

时间:2016-07-17 02:05:15

标签: dictionary f# covariance idictionary

type TypeA () = class end
type TypeB () = inherit TypeA ()

// "The type 'TypeA' does not match the type 'TypeB'":
let iDict : IDictionary<TypeA, bool> = [ TypeB (), true; TypeB (), false ] |> dict

let d = Dictionary<TypeA, bool> ()
// This is OK, though:
d.Add (TypeB (), false)

为什么IDictionary键与派生类型不兼容?

1 个答案:

答案 0 :(得分:2)

让我们看看两种方法之间的差异:

在第一种情况下,您正在创建一个列表:

[ TypeB (), true; TypeB (), false ]

此类型为(TypeB * bool) list

dict函数的类型为seq<'Key * 'Value> -> IDictionary<'Key,'Value> (requires equality)

因此,应用dict函数

dict [ TypeB (), true; TypeB (), false ]

会产生IDictionary<TypeB, bool>类型的值。

IDictionary<TypeB, bool>不等同于IDictionary<TypeA, bool>,这些是完全不同且不兼容的类型,因此编译错误。

如果您想以这种方式从更多派生类型的集合中初始化字典,则必须明确地进行上传,例如:

let iDict = 
    [ TypeB (), true; TypeB (), false ] 
    |> List.map (fun (a,b) -> (a :> TypeA), b) 
    |> dict

在您的第二个示例中,此问题从未实现,因为您最初创建了Dictionary<TypeA, bool>

然后使用Add方法将TypeB的内容添加到字典中。由于Add是一种方法,因此F#可以对参数执行自动向上转换,以便TypeB的值自动转换为TypeA