最新发布的.NET不可变集合中包含了 ImmutableArray
ImmutableArray
Immo Landwerth 提出了以下建议:
使用不可变数组的理由:
- 极少更新数据,并且元素数量很小(小于 16)
- 对迭代数据的性能要求很高
- 有很多不可变集合的实例,并且无法负担将它们全放在树中的开销。
仍然使用不可变列表的理由:
- 更新数据比较常见,或者元素数量预计不会太小
- 对更新集合的性能要求比迭代要高
作为一个值类型,ImmutableArray
重大改变
不可变集合正处于开发过程中,重大变更时有发生。这一次,我们看到 Create
Immo 写到,
我们发现接受 IEnumerable
参数的重载可能会产生意想不到的结果。你可能认为要通过其他集合创建集合可以使用接受 IEnumerable 参数的重载: 但你最终创建的是 ImmutableList<List
> 而不是 Immutable ,这是因为在进行重载决策时,参数重载的优先级要高于从 List 到 IEnumerable 的隐式转换。 因此我们决定将所有操作 IEnumerable
的工厂方法改名为 From,以消除这种歧义。
最初的 IImmutableList
扩展方法 GetValueOrDefault 曾经接受一个 IDictionary<TKey, TValue> 或 IReadOnlyDictionary<TKey, TValue>。如果实际的类同时实现了这两个接口就会引起编译器错误,因此用只接受 IImmutableDictaionary<TKey, TValue> 的版本进行了替换。
其他改变
IImmutableSet
不可变集合仍然是预览版,并且不允许在生产中使用。它们目前可用于.NET 4.5、Windows Store、Windows Phone 8 和 Portable Class Library。
数组的性能
Jon Skeet 最近测试了数组的性能并发现了一些有趣的结果。用包装器包装数组竟然可以使它们能够更快地写入。对一个包含 100 项的数组进行 1 亿次写入,字符串数组用了 40.865 秒,而包装的字符数组只用了 29.338 秒。读取速度两者差不多,字符数组用了 12 秒,包装的数组用了 11.843 秒。
其原因要追溯到 Java 了。Java 的数组是协变的,也就是说可以将一个 String[] 传递给任何期望 Object[] 的参数或变量。.NET 的运行时 CLR 要设计为支持 Java,所以也支持协变数组。因此在每次写入数组时 CLR 都需要执行一次类型检查。
Jon Skeet 的数组包装器与我们上面提到的 ImmutableArray 中使用的并不相同。它在内部对数组中的每一项使用了基于结构的包装器。由于它只是一个包含了指针的结构,因此并不比数组中存储的普通引用耗费更多的空间。但其设计可以使 CLR 的 JIT 编译器忽略类型检查。
评论