2012-12-22 419 views
2

微软已经使用结构如下规则:C#类VS结构

考虑定义一个类的结构,而不是如果 类型的实例是小的和普遍短命或通常嵌入在 其他物体。

不要定义的结构,除非该类型具有所有以下特征:

  1. 它在逻辑上表示单个值,类似于原始类型(整数,双,和等等)。
  2. 它的实例大小小于16个字节。
  3. 它是不可变的。
  4. 它不会经常被装箱。

据我了解,你当你想要一个价值型行为创建结构。当然,这可以让您在分配和传递给函数时复制开销。但你为什么要追随#2和#3?如果你的价值类型太大了会怎么样?此外,我不明白你为什么会将不可变类型作为值类型。如果类型是不可变的,那么最好通过引用来节省时间,因为无论如何它都不能被改变。

我问的原因是我在做一个游戏,其中对象具有像Vector2d类型的坐标,速度等属性。问题是,我应该使Vector2d不可变结构体(不需要大量额外的内存吗?),可变结构体(人们说它们是邪恶的)或者只是类(我将不得不始终调用vector.Clone(),否则我可能会无意间得到两个具有相同向量变量的对象)

+2

_“如果你的值类型太大?”_根据MS,你应该使用*类* ... – gdoron

+1

[为什么是可变结构邪恶?](http://stackoverflow.com/questions/441309/why-are-mutable-structs-evil) – GSerg

+3

[你应该只根据你面对的实际问题提出实际的,可回答的问题。](http://stackoverflow.com/faq#dontask)那么你的实际题? –

回答

0

对于#2,不应轻易复制大型结构,因此大部分时间都应该是类。而且,这些并不是硬性规则,只是经验法则。如果您有充分理由不遵守规则,请继续。

2

此外,我不明白你为什么会将不可变类型作为值类型。

int类型是不可变的类型,是您为什么需要不可变值类型的理想例子。

想象一下,如果int是参考类型。如果您每次使用整数都必须解除引用,那将非常昂贵。事实上,当你使用“盒装”整数(例如存储在类型为object的变量中的整数)时会发生什么情况。在.NET中与Java相比的一个改进是集合可以容纳非盒装整数。

如果类型是不可变的,你会更好地节省时间供参考

是,如果是大的和不可改变的,那么你会节省时间通过引用传递它传递。这就是为什么指导方针建议大类型应该是参考类型。

+0

如果有一个int [1]包含值0xBABE1234,则一个线程使用BlockCopy来用0xCE覆盖第一个字节,而另一个线程使用BlockCopy来覆盖第二个字节0xFA,使得数组元素现在保存0xBABEFACE,第一个数组元素做了什么,如果它没有变异?像0xBABEFACE这样的值可能是不可变的,但是一个值类型并不真正保存一个值;它包含一组字节并定义这些字节如何解释为一个值。 – supercat

-1
  1. 当传递/操纵一个结构体时,它的整个值必须在堆栈周围而不是仅仅引用。一旦它达到一定的大小,16个字节,考虑只使用一个类来避免开销。

  2. 不变性更多的是旨在减少代码错误的模式,而不是一条硬性规则。如果你的值类型可能是不可变的,那么可以这样做。

您可能会误解不可变性。您的变量可以更改值,但值本身不会更改。例如,您可以拥有一个Datetime变量并将其设置为任何其他DateTime实例,但实际上在实例初始化后无法更改它们的字段。

+0

如果一个类型应该提供值语义,那么任何引用类型的实现都必须是不可变的。如果有一个实例并且希望有一个实例几乎相同,除了“Bar”等于6而不是5,必须创建一个新实例,该实例包含来自旧实例的所有数据的副本(“Bar”除外,新的应该是6)。值类型应该是不可变的想法源于值类型方法应用于只读实例的方式中的问题。好的解决方案不是制造所谓的“不可变”值类型(实际上不是),而是...... – supercat

+0

......反而认识到如果像“Sphere3d”这样的类型应该代表四重奏“浮动” '值,('X','Y','Z'm和'Radius'各一个),这个类型应该只显示这些值作为字段;任何使用该类型实例的代码应该执行相同的验证,就像它已经分别接收这些参数一样。对属性的不必要的包装可能导致显着的减速,随着结构变得更大而变得更糟,并且对导致一些人提出结构应该是不可变的概念的狡诈语义负责。 – supercat

1

16个字节似乎有些随意,但可能与典型CPU的高速缓存行大小有关。这比现代CPU上的64字节缓存线要小很多。可能是因为你不能明确地将你的结构对齐到一行。

保持您键入不可变再次避免需要通过引用传递。而只是返回一个新的实例。以下引用比使用缓存值的成本要高得多,保持较小的值会增加缓存中的机会。

一般来说,如果你想引用语义使它成为一个类,否则使它成为一个结构。我建议你遵循MS准则,除非你能证明使用一个分析器(或其他一些经验证据),否则有很好的理由。

+1

.net框架优化了16个字节和更小的结构的复制,以便复制17个字节的结构将比复制16个字节的结构慢得多。尽管如此,如果一个类型应该表现出值语义并且通常会被分段修改,那么一个正确使用的暴露字段结构通常可以提供比任何其他类型更好的性能。在某些情况下(例如,分段修改几乎与常见的一样 - 如果不是更多的话) - 任何大小的*暴露字段结构将提供比类更好的性能;结构越大,差异越大。 – supercat