由于结构是值类型,因此当作为参数传递给方法时,它们的数据被复制。例如:
int someInt = 7;
DoSomeMethod(someInt); // <-- This is passing the "value" 7.
到目前为止,很容易理解,你可能想知道我的问题是如何有效的...所以请考虑以下几点:
public struct TimmysStructOfGoodness
{
public int SomeInt1;
public int SomeInt2;
public int SomeInt3;
// ... later that day ...
public int SomeInt999;
}
然后,参考以下代码:
TimmysStructOfGoodness someStructOfGoodness = new blah blah blah...
DoSomeMethod(someStructOfGoodness); // <-- **HERE IS WHERE THE QUESTION APPLIES!**
上述语句是否尝试分配几个ram来“复制”我的值类型(struct)?
如果答案是肯定的 - 那么何时/哪里是“更快”和“更慢”之间的界线?
如果不是 - 那为什么不呢?因为我所知道的价值类型,这应该是一个问题。
主要免责声明:我知道这与你为什么要使用一个类的结构无关,而且我知道我永远不会用999个字段创建一个结构 - 这只是一个基本的内部和内部的问题之类的:)
答案 0 :(得分:12)
(更新,感谢其他用户的贡献)
与class不同,struct是在堆栈上创建的。因此,实例化(和销毁)结构比使用类更快。
除非(正如Adam Robinson指出的那样)struct是一个类成员,在这种情况下,它与堆中的所有其他内容一起分配。
另一方面,每次分配结构或将其传递给函数时,都会复制它。
我认为结构大小没有硬性限制。成千上万的字节肯定太多了。 MSDN says:
除非您需要参考类型 语义,一个较小的类 超过16个字节可能更有效 由系统处理为结构。
这是 - 如果你需要通过引用传递它,使它成为一个类,无论大小。
在第二个想法中,你仍然可以通过在函数参数列表中指定ref来传递struct。
因此,如果通过引用传递它并将其用作类成员,那么大型结构实际上可以正常。
答案 1 :(得分:9)
结构和类不仅具有不同的性能,它们的行为也不同。您应该使用最适合您正在实现的类型的那个。何时使用其中一个的准则是clearly described on MSDN。仅在满足以下所有条件时才使用结构:
如果要将结构传递给函数,您将获得它的副本。如果你的结构很大,那么它将导致复制大量数据。引用通常实现为4个字节(在x86上),因此传递对象只需要复制这4个字节。
另请注意,上述指南要求结构很小。
答案 2 :(得分:6)
结构的性能影响取决于您如何使用此类结构。
关于结构是否比引用类型更快或更慢,不可能做出明确的陈述。这一切都取决于你如何使用它们,以及在什么情况下。
结构(一般的值类型)最终可以在堆栈或堆上分配 - 具体取决于它们的声明上下文。如果在方法的主体中声明它(并且没有明确地将其封装),结构将最终在堆栈上。如果然后将该结构传递给按值接受它的方法(如在您的示例中),它确实将被复制 - 但在堆栈上。堆栈上的分配是一个非常有效的过程(BTW,.NET堆也非常有效) - 但它是一个复制过程。
当然,您可以使用ref / out传递结构 - 在这种情况下不会发生复制 - 对结构的引用将传递给方法。这可能是,也可能不是,因为它将允许被调用的方法改变结构的内容。
声明为类成员的结构实际上将在堆上分配(作为类的内存布局的一部分)。如果您传递该类,则不会复制该结构,但仍可通过类引用访问该结构。
您还可以通过显式装箱将结构体添加到堆中:
object x = new MyStruct( ... ); // boxed on the heap
Jon Skeet有一个很好的article about where things end up in memory你应该阅读。
答案 3 :(得分:3)
为了增加混乱,请记住,如果您不需要将副本传递给另一个方法,您始终可以通过引用传递结构以避免复制...
答案 4 :(得分:2)
你的问题的答案是:是的。定义结构时,每个赋值都会产生一个复制操作。
没有确切的行将“快”和“慢”分开,因为有很多因素影响速度WRT到结构,例如:
&LT;校正&GT; 结构按值存储在堆栈上或包含对象内。因此,它们会提升缓存局部性,因为相关页面已经加载到CPU的缓存中,而任意堆页面很可能都没有。 &LT; /校正&GT;此外,结构不允许方法覆盖,因此方法调度也(稍微)更快。
另一方面,每个作业都会产生一份副本。因此,如果您的代码有很多分配,那么上述优势将被复制操作的成本所抵消。从一个程序到另一个程序的收支平衡点不同(由于缓存局部性,方法调度和分配的不同特征)