关于c#:关于Structs的问题

Questions about Structs

msdn说16字节或更小的类最好作为结构[引用]来处理。为什么会这样?这是否意味着,如果一个结构超过16个字节,它的效率会低于一个类,还是相同?如何确定类是否小于16个字节?什么限制结构像类一样工作?(除了不允许无参数构造函数)


这个问题有几个不同的答案,有点主观,但我能想到的一些原因是:

  • 结构是值类型,类是引用类型。如果您使用16个字节作为总存储空间,那么为每个字节创建内存引用(4到8个字节)可能是不值得的。
  • 当您有非常小的对象时,通常可以将它们推到IL堆栈上,而不是对对象的引用。这确实可以加快一些代码的速度,因为您正在消除被调用方的内存取消引用。
  • 在IL中有一些与类相关联的额外"fluff",如果您的数据结构非常小,那么无论如何都不会使用这些fluff,因此它只是您不需要的额外垃圾。

但是,结构和类之间最重要的区别是,结构是值类型,类是引用类型。


通过"高效",他们可能在谈论表示类或结构所需的内存量。

在32位平台上,分配对象至少需要16个字节。在64位平台上,最小对象大小为24字节。因此,如果您仅仅从使用的内存量来看它,那么包含少于16字节数据的结构将比相应的类"更好"。

但记忆的使用量并不是整个故事。值类型(结构)与引用类型(类)根本不同。结构可能不方便使用,如果不小心,实际上会导致性能问题。

当然,真正的答案是使用在你的情况下最有效的方法。在大多数情况下,使用类会更好。


检查这个链接,我在so today.net类型的内部构件中的一个答案上找到了它。您还可以尝试搜索so,并通过google搜索"引用类型与值类型"来查找结构和类之间的差异。

What restricts a struct from acting like a class?

< /块引用>

有很多不同之处。例如,不能从结构继承。

不能有虚拟方法,因此不能使用结构来实现接口。结构中的实例方法可以访问结构的私有字段,但除此之外,它们的行为非常类似于辅助"helper"函数(对于不可变结构,它们有时甚至不需要访问私有数据)。所以我发现它们不如类方法那么"有价值"。


复制结构的实例比创建类的新实例和从旧实例复制数据花费的时间要短,但类实例可以共享,而结构实例不能。因此,"structvar1=structvar2"需要复制新的结构实例,而"classvar1=classvar2"允许classvar1和classvar2引用同一个结构实例(不必创建新的结构实例)。

用于处理新结构实例创建的代码针对最大16字节的大小进行了优化。较大的结构处理效率较低。如果每个拥有结构的变量都将拥有一个独立的实例(即没有理由期望任何特定的两个变量将拥有相同的实例),那么结构就是一个胜利;如果许多变量可以拥有相同的实例,那么结构就不是一个胜利(如果它们是一个胜利的话)。


结构与类不同,因为它们存储在堆栈上,而不是堆上。这意味着每次调用以结构为参数的方法时,都会创建一个副本并传递给该方法。这就是为什么大型结构非常低效的原因。

不过,我还是不鼓励使用结构,因为它可能会导致一些细微的错误:例如,当您更改结构的字段时,它不会反映给调用方(因为您只更改了副本),这与类的行为完全不同。

所以我认为16个字节是结构的一个合理的最大大小,但在大多数情况下,最好是有一个类。如果仍要创建结构,请尝试使其不可变。


这是因为clr处理结构和类的方式不同。结构是值类型,这意味着它们位于堆栈上而不是托管堆中。保持结构小是一个很好的经验法则,因为一旦开始将它们作为方法参数传递,当结构在传递给方法时被整体复制时,就会产生开销。

由于类将其引用的副本传递给方法,因此当用作方法参数时,它们所产生的开销要少得多。

确定类大小的最佳方法是,将类的所有成员所需的字节总数加上clr开销的额外8个字节(同步块索引和对对象类型的引用)。


在内存中,结构将直接保存数据,而类的行为更像指针。这本身就有一个重要的区别,因为将结构作为参数传递给方法将传递其值(在堆栈上复制它们),而类将传递对值的引用。如果结构很大,您将在每个方法调用上复制大量的值。当值非常小时,复制值并直接使用它们可能比复制指针并从另一个地方获取它们要快。

关于限制:不能将其指定为空(尽管可以使用nullable<>),必须立即初始化它。