8

当我意识到 F#map实现了 IDictionary<'Key, 'Value> 并ICollection<KeyValuePair<'a, 'b>>考虑到两者都支持突变(添加和删除)作为合同的一部分时,我有些惊讶。

map只看它的实现,当你试图引起突变时除外!

let map = [| (1, "one"); (2, "two") |] |> Map.ofArray
let dict = map :> IDictionary<int, string>
dict.Add(3, "three");;

上面的代码抛出异常:

System.NotSupportedException:地图值不能被改变。在 Microsoft.FSharp.Collections.FSharpMap 2.System-Collections-Generic-IDictionary2-Add(TKey k, TValue v) at .$FSI_0007.main@() 由于错误而停止

这是预期的。

对于一个不可变集合来说,能够将自己暴露为一个可变集合,只是为了在该集合的消费者试图引起突变时抛出异常,这似乎是一个危险的决定。

我在这里错过了什么吗?

4

3 回答 3

9

我认为主要原因是.NET 没有任何表示不可变(a 接口的一部分)字典的接口。这意味着所有 .NET API 都必须IDictionary<K, V>作为参数,即使它们只打算从字典中读取。所以:

  • 实现IDictionary<'K, 'V>几乎是使 F# 不可变映射可用作任何需要支持查找的对象的 .NET 库的参数的唯一方法。遗憾的是,.NET 中没有只读选项。

  • 实现ICollection<KeyValuePair<'K, 'V>>对我来说没有太大意义,因为有一个只读的替代方案IEnumerable<KeyValuePair<'K, 'V>>,不可变的映射也实现了这个接口。

    但也许有一些 .NET 库采用ICollection<'T>(为了提高效率 - 即在Count不枚举所有元素的情况下获取)并以只读方式使用它。

    编辑:正如丹尼尔在评论中指出的那样,实现ICollection是必需的,因为IDictionary接口继承自它。

我认为缺少只读接口是很不幸的,但可能无法解决这个问题,因为这意味着更改现有的 .NET 集合库。

于 2012-06-20T13:59:37.317 回答
6

IsReadOnly允许接口是只读的,即使它提供了可写的方法。

于 2012-06-20T15:39:17.593 回答
4

这是一个 .Net 的东西。您不能只实现某些接口,但他们想要实现该IDictionary`2接口 - 因为您可以使用它的查询和转换方法(因此您可以将它传递给从 读取的函数IDictionary`2)。

于 2012-06-20T13:18:08.527 回答