【问题标题】:Readonly struct vs classes只读结构与类
【发布时间】:2019-01-21 00:40:41
【问题描述】:

假设你只有不可变类型 并且您的所有代码都已更新到 C# 7.3,并且您的方法使用 in 关键字作为输入

为什么你会使用类而不是只读结构?

使用结构的缺点是复制成本很高,但假设您防止任何复制(防御性编译器复制或由代码表示),只读结构允许您仅复制引用(就像类一样)并避免堆分配和压力在垃圾收集器上。

排除特殊情况(我猜它可能是一个无法放入堆栈的非常大的对象)您通常会使用只读结构作为首选吗?

我感兴趣的案例是将它们用作数据容器。

【问题讨论】:

  • 因为你想通过引用访问和编辑同一个对象?
  • 选择structclass,首先要根据您是想要value 语义还是reference 语义来选择。
  • 您采用了有限范围的用例,并尝试根据它们提出一般性问题。引用类型不仅仅是数据容器。
  • 结构应该代表。具有相同字段值的结构的所有实例都是“相同的”并且可以互换(例如,所有5s 都是相同的)。类代表对象。他们有一个固有的“身份”,这不是他们包含的数据的一部分。即使您有两个具有相同数据的实例,它们至少在某些方面也不“相同”。
  • @jrh - 是的,他们会在很多方面表现得那样。不过,我仍然可以将它们与老 ReferenceEquals 分开 :-)

标签: c# .net


【解决方案1】:

不应将结构视为“廉价对象”;它们具有相似的特征集,在某些区域重叠而在其他区域不相交。例如:

  • 结构不能参与多态性
  • 如果不对结构进行装箱,就不能将其视为接口的实例(警告:“受约束的调用”,但这仅在某些情况下有效)
  • 很多库 API不能很好地工作(或者可能根本不能)使用结构 - 他们期望可变的 POCO;您可能想要使用库从数据库中获取数据、序列化数据或在 UI 中呈现数据 - 所有这些都被结构体所困扰
  • 结构不适用于某些模式,例如树或兄弟关系(Foo 不能包含 Foo,如果它是结构) - 还有其他的
  • 结构和不可变类型通常难以使​​用

另外,请注意,直到最近(“ref 返回”和“ref locals”),很难实现“只读结构允许您只复制引用”的某些部分;这现在简单多了。

但坦率地说,在大多数情况下,POCO只是更容易使用,并且适用于大多数应用程序代码场景。

在某些时候结构体确实是一个了不起的选择。只是不是每次。但是,我支持这样一种观点,即如果您要使用 struct,它应该是 readonly struct(默认情况下)或 ref struct(如果您知道为什么'正在做);可变的非ref 结构是痛苦的秘诀。

【讨论】:

  • 所有有效积分,谢谢。我是否必须选择在这种情况下都不适用的情况下,您会建议盲目地将只读结构作为默认选择吗?除了上述观点,您提到的哪些案例使它们难以工作?
  • @user4388177 数据在您的代码期间经常需要更改的现实是一个大问题:) 尤其是当数据位于List<T> 之类的东西中时,它没有“参考返回” API(并且不能明智地这样做,因为如果有人调用 Add 并强制底层数组增长,人们会期望 ref 指向 active 数组,但现有 refs实际上是指向 old 数组的内部指针)。这意味着你不能只做myRef = myRef.WithSomeChangedProperty("foo");(覆盖值)
  • 这是有道理的,但我越来越倾向于采用更具功能性/不可变的设计方法。当我必须创建一个类型并且我想强制它的不变性时,我相信 readonly struct 可能是一个很好的选择。列表和数组(即使您使用不可变版本)大部分时间都属于“大对象”类别,所以我不会梦想在那里使用结构。
  • @user4388177 用于列表,不过 - 如果 GC 是您关心的问题,您可能 想要考虑池 see here for context(查找“Here's the gist”以获取实际代码 uesd )
  • 是的,我们使用 ArrayPool,非常有用。谢谢。我不知道有一个关于列表池的 GitHub 问题,很有趣。尽管我们最终在生产中遇到了一些错误,这些错误来自以前的迭代 XD。
猜你喜欢
  • 2018-06-27
  • 1970-01-01
  • 1970-01-01
  • 2011-07-26
  • 1970-01-01
  • 2015-09-29
  • 1970-01-01
相关资源
最近更新 更多