我在我的应用程序中使我的大部分基本类型都是不可变的。但是集合也应该是不可变的吗?对我来说,这似乎是一个巨大的开销,除非我错过了什么。
我说的是保存 Point3 值等的集合,这些集合可以在不同时间添加。因此,如果一个集合中有 1M 个值,而您需要删除其中的 1 个,则必须重新创建相同的集合,对吗?
我在我的应用程序中使我的大部分基本类型都是不可变的。但是集合也应该是不可变的吗?对我来说,这似乎是一个巨大的开销,除非我错过了什么。
我说的是保存 Point3 值等的集合,这些集合可以在不同时间添加。因此,如果一个集合中有 1M 个值,而您需要删除其中的 1 个,则必须重新创建相同的集合,对吗?
Eric Lippert 有一个关于 C# 中的不可变性的系列,如果你通读它,他实现了几个不同的不可变集合:
不可变集合很棒,特别是如果您的应用程序已经利用不可变类型或语义。
.NET 刚刚发布了他们的第一个不可变集合,我建议您尝试一下。
我最喜欢的收藏技巧就是永远不要传递它们。如果它们只存在于单个对象中,那么使它们不可变几乎是无关紧要的(只要您的包含对象不改变它们,它们就不会改变)。
通常你的收藏代表了一些东西,对吧?它是一组狗或一组发票......
通常,您可以对一组狗(牧群?中性?)或一组发票(支付?)做一些事情,实际上总是有适用于整个对象列表的操作 - 具有超出单数功能的操作invoice.pay() (例如,确保首先支付最重要的发票),如果没有围绕您的集合的类,则实际上没有放置这些操作的地方。
将一些变量与您的集合相关联通常也很有意义——同样,如果没有包装器,您最终总是将这些变量放在一些奇怪的不自然的位置。
起初它可能看起来很奇怪,但在你判断之前尝试几次。
如果您只从开头或结尾添加/删除,您可能会作弊 - 但一般来说;是的:这意味着您需要为每次更改创建一个新集合。
那么:你需要(有效地)改变集合吗?如果是这样,并且考虑到它们的大小:我很想查看同步访问(而不是使它们正确地不可变)。看lock
(又名Monitor
)。
我同意 Eric 关于为问题选择正确工具的评论。当您的目标包括提供清晰的身份语义或使您的实现更易于在并行计算环境中使用时,不变性会增加价值。不变性还可以通过允许缓存或透明代理等优化来帮助提高性能。
另一方面,不变性也会产生性能成本——尤其是当您使用“写时复制”模式来模拟“更改”时。
你必须决定为什么你希望你的实体/集合是不可变的——这将有助于你决定是否这样做。
查找表将构成一个体面的不可变集合。它不需要改变大小,并且您希望它是静态的,因此可以快速查找棘手的计算。如果您以后需要添加一些东西,那么我就不会为不变性而烦恼,它会破坏目的。
这取决于您的程序编写/设计的风格。
不可变集合只有在您以受函数式编程影响的风格进行编程时才有意义(命令式设计的程序不应该使用它们)。
就像在函数式语言中一样,您应该使用链接列表,然后可以在每个元素 ( cons
) 中构建 O(1) 并以功能方式处理它们(递归,从列表构建新列表)。
当您的程序需要命令式集合(数组、向量/列表)时,请保持它们是可变的。
您可以将您的公共接口定义为 IEnumerable,但仍然在您的实现中使用可变集合。
这完全取决于谁同时使用这些集合。字符串是不可变的,以防止 boo-boo 像两个线程试图同时删除第一个字符。
如果您有一个可以在构建后添加项目的集合,则它不是不可变的