不可变类与不可变结构

时间:2011-08-17 00:59:50

标签: c# immutability

我有一个开始生活可变的课程,但我已经让它变得一成不变了。我应该将其更改为struct吗?选择一个而不是另一个需要考虑哪些因素?我的特殊情况是Point类型类(它表示自定义坐标系中的坐标),它由4个int字段组成,还有一些属性以不同方式访问相同的数据。我注意到String是一个类并且是不可变的,因此必须有一些用例。

7 个答案:

答案 0 :(得分:6)

通常,不,您不应将其更改为结构。仅仅因为它是不可变的并不意味着它自动成为一个结构的良好候选者。

结构应该很小。使用四个整数时,它只是建议的16字节限制,结构的性能开始下降。

结构应该代表某种形式的单个实体。也许你的班级会这样做,但从你的描述来看,这听起来不太可能。

结构比类更难正确实现。它应该在比较等方面表现得很好,所以要实现的东西比预期的更多。

除非您有充分的理由将其作为结构实现,例如性能问题,否则您应该将您的类保持为类。

答案 1 :(得分:4)

据我所知,使用结构而不是类是一个优化问题。结构存储在堆栈而不是堆中,因此它们非常适合作为大量使用的多个字段的轻量级包。无论何时在方法之间传递它们都会被复制,这使得传递它们变得更加昂贵 - 但这可能会影响您对不可变性的渴望。使用结构的缺点包括语言强加的自然限制。

我根本不是这方面的专家,但想要提出这方面的意见。拥有更多经验的人当然应该介入并扩展这一点。此外,这里有一个有用的讨论:When to use struct?

最终我会说,如果不变性是你唯一的考虑因素,请保持一个阶级(特别是现在我看到其他人表达了这种观点)。无论是否为结构,都可以实现不变性,因此这个问题看起来并不相关。

答案 2 :(得分:2)

如果它很小且不可变,那么将它作为结构将是更可取的。特别是如果你要收集很多积分。如果你有一个100万点的列表,那么就GC时间和每个对象实例的16字节额外开销而言,所有这些对象都会有很多开销。

String必须是引用类型,因为您不能并且不希望在堆栈上存储可变数量的字符,更不用说实习字符串和共享实例的能力。这个msdn article提供了有关为什么Tuple成为引用类型的信息。

答案 3 :(得分:1)

将它保持为类,除非它足够小以至于结构有意义。这将是罕见的。我的想法是,一般而言,“结构性”的案例正在迅速减少。如果在语言的开头(不变性和域值对象特征)中出现了更强的语义,我就会改变主意。作为一个相当新的例子,考虑System.Tuple<&gt ;.也就是说,我会通过询问,你的对象(修辞地说)来略微对冲。

答案 4 :(得分:0)

这实际上取决于您想要/需要表示其中包含的数据的内容。结构通常用于简单表示或用于保存您可能需要反复使用的多个值,并且当对象本身具有需要完成的某些必需行为时,应使用类。在您的情况下,为了简单起见并允许您保留您的属性,您也可以将其作为一个类。

在某些情况下使用不变性。例如,如果您希望每次更改时都有一个全新的对象,那么您可能需要考虑不变性(数据约束等)。如果你想能够通过一个你不想改变的非常具体的信息传递一个类(可能是数据库中的一些DTO对象只是创建然后传递而没有改变),这样你就不会得到奇怪的行为。有人改变了价值。

答案 5 :(得分:0)

我不会改变为不可变形的结构。 struct和class之间最大的区别是struct是值类型而class是引用类型。传递给方法时会复制结构,但传递给方法的类将通过引用传递。类和stucts一样,类也可以是不可变的。

答案 6 :(得分:0)

不可变结构和密封的不可变类类型对象的语义几乎相同。结构16字节和更小的性能通常会优于其他相同的类型对象的性能,除非这些结构是对象或接口类型的类型转换;这种类型转换将极大地降低结构的性能,但不会特别影响类类型的性能。请注意,:

之间存在巨大差异
  void doSomethingWithIFoo(IFoo whatever);

  void doSomethingWithIFoo<T>(T whatever) where T:IFoo;

将结构传递给前者需要将结构类型转换为接口类型,而第二种形式将允许将结构作为自己的类型进行处理。