不变对象是好的做法吗? [关闭]

问题描述 投票:21回答:5

如果可能的话,我应该让我的班级保持不变吗?

我曾经读过约书亚·布洛赫(Joshua Bloch)的书《有效的Java》,他建议出于各种原因使所有业务对象不可变。 (例如线程安全)这也适用于C#吗?

您是否尝试使对象不可变,因此使用它们时遇到的麻烦更少了?还是不值得您创建它们带来不便?

c# .net immutability
5个回答
25
投票

不可变的埃里克·利珀特(Eric Lippert)为此主题写了whole series of blog posts。第一部分是here

引用他链接到的earlier post

旁听:不可变的数据结构是C#的未来之路。如果您知道数据结构永远不会改变,那么就更容易进行推理了。由于无法修改它们,因此它们是自动线程安全的。由于无法修改它们,因此您可以维护该结构的过去“快照”堆栈,突然之间,撤消重做实现变得微不足道。不利的一面是,它们的确会消耗内存,但是,嘿,这就是垃圾回收的目的,因此请不要费力。


4
投票

这将是更多意见类型的答案,但是...

我发现理解程序的容易性,即维护和调试所述应用程序,与在处理每个组件期间发生的有状态转换的数量成反比。在我脑海里徘徊的状态越少,编写算法时我就越会关注算法中的逻辑。


2
投票

不可变对象是功能编程的主要特征;它有自己的优点和缺点。 (例如,链表实际上不可能是不变的,但不变的对象会使并行性变成小菜一碟。)因此,如对您的帖子的评论中所述,答案是“取决于”。


2
投票

脑海中,我想不出不变对象使线程安全代码“更好”的原因。

如果我希望对象是线程安全的,则可以在它周围加一个锁,也可以对其进行复制,并在完成处理后更新引用。通常,我不想每次更改都会有一个新对象。

对我来说,不可变的字符串给线程带来了更多麻烦,而不是它带来的帮助。

实际上,我使用内置String.ToUpper()的不安全代码制作了一个“就地”“ ToUpper”。它的运行速度大约提高了4倍,并消耗了峰值内存的1/2。


0
投票

不可变结构的另一个不错的好处是,您可以在本地缓存它们的实例,并在多个线程中重用它们,而不必担心意外的行为,就像可变的情况一样。

例如,假设您正在使用外部缓存服务,例如memcached或Velocity或其他一些同样简单的分布式哈希表服务。您可以只使用C#客户端库并将其称为足够好。但是,如果给定短暂的上下文(例如Web请求场景),那将浪费资源。您真正想要的是在上下文中一次从缓存中提取每个对象。

完成这项工作的最安全的方法是将本地哈希表放在您的进程中的缓存提供程序的前面。在第一次请求缓存键时,您将下拉表示您要使用的对象的序列化字节流,并将该字节流存储在本地哈希表中。在对相同缓存键的后续请求中,只需在本地哈希表中查找字节流,然后针对每个请求将对象反序列化为一个新实例。这是为了防止对于相同的信息(假定在您的上下文的生命周期内没有更改),多次到达缓存服务器节点进行冗余旅行。

使用不可变结构,您可以在第一个请求上仅对字节流进行反序列化一次,而不必将反序列化的实例(而不是字节流)存储在哈希表中,而只共享对象的单个不变实例。显然,这减少了反序列化的惩罚,如果您使用的代码以这种方式编写而不必关心它对缓存提供程序的调用次数,那么就可以相当快地加起来。

也许这更多是一个主观的答案,但这是一个特定的问题,可以通过使用不可变的结构来唯一地解决,因此我认为与共享有关。

© www.soinside.com 2019 - 2024. All rights reserved.