什么时候应该在C#中使用结构而不是类?我的概念模型是,当项只是值类型的集合时,使用结构。一种将它们逻辑地结合在一起的方法。

我在这里遇到了这些规则:

结构应表示单个价值结构应具有内存占用空间小于16字节。结构不应在之后更改创造

这些规则有效吗?结构在语义上意味着什么?


当前回答

当您需要值语义而不是引用语义时,请使用结构。

如果需要引用语义,则需要类而不是结构。

其他回答

神话1:结构是轻量级类

这个神话有多种形式。有些人认为价值类型不能或不应该有方法或其他重要的行为,它们应该简单地使用数据传输类型,只有公共字段或简单的财产。DateTime类型是这是一个很好的反例:就存在而言,它是一种价值类型是有意义的一个基本单位,如数字或字符能够基于其值执行计算。从另一个角度看问题方向,数据传输类型通常应该是引用类型应该基于期望的值或引用类型语义,而不是类型。其他人认为价值类型比参考类型“更轻”性能。事实是,在某些情况下,价值类型更有表现力-它们不需要垃圾收集,除非它们是盒装的,没有类型例如,识别开销,并且不需要取消引用。但在其他方面方法,引用类型是性能更高的参数传递,将值分配给变量、返回值和类似操作只需要4或8个字节即可复制(取决于您运行的是32位还是64位CLR),而不是复制所有数据。想象一下,如果ArrayList是一个“纯”值类型,并且将ArrayList表达式传递给涉及复制其所有数据的方法!在几乎无论如何,性能并不是由这种决定决定的。瓶颈几乎永远不会出现在你认为会出现的地方,在你根据性能做出设计决策之前,你应该衡量不同的选择。值得注意的是,这两种信念的结合也不起作用。它不管一个类型有多少个方法(无论是类还是结构)-每个实例占用的内存不受影响。(内存方面有成本为代码本身占用,但这只发生一次,而不是每个实例。)

神话#2:引用类型存在于堆中;堆栈上存在值类型

这通常是由于重复的人的懒惰造成的部分是正确的,引用类型的实例总是在堆上创建的。这是导致问题的第二部分。正如我已经注意到的,变量的值存在于声明的任何地方,因此,如果您有一个类的实例变量类型为int,那么任何给定对象的变量值将始终位于该对象的其余数据的位置在堆上。仅局部变量(方法中声明的变量)和方法参数存在于堆栈中。在C#2和更高版本中,即使是一些局部变量在堆栈上生存,正如我们在第5章中研究匿名方法时所看到的那样。这些概念现在是否相关?如果您正在编写托管代码,那么应该让运行时考虑内存的最佳使用方式,这是有争议的。事实上,语言规范并不能保证哪里未来的运行时可能能够在堆栈上创建一些对象,如果或者C#编译器可以生成几乎不使用堆栈。下一个神话通常只是一个术语问题。

神话#3:默认情况下,对象在C中通过引用传递

这可能是流传最广的神话。再一次,制造这个的人声明经常(虽然不总是)知道C#的实际行为,但他们不知道“通过引用传递”的真正含义。不幸的是,对于那些知道这意味着什么。引用传递的形式定义相对复杂,涉及l值和类似的计算机科学术语,但重要的是,如果你通过了变量,您调用的方法可以通过更改其参数值来更改调用者变量的值。现在,请记住引用的值类型变量是引用,而不是对象本身。您可以更改参数引用的对象,而不通过引用传递参数本身。例如,以下方法更改StringBuilder的内容对象,但调用方的表达式仍将引用与之前:

void AppendHello(StringBuilder builder)
{
    builder.Append("hello");
}

调用此方法时,参数值(对StringBuilder的引用)为通过值传递。如果要在方法,其中语句builder=null-改变不会是与神话相反。有趣的是,不仅神话中的“引用”部分不准确,而且“对象被传递”部分也不准确。对象本身也不会被传递通过引用或通过值。当涉及引用类型时通过引用传递,或者参数(引用)的值通过值传递。除此之外,这回答了当null为如果正在传递对象,则用作by-value参数,这将导致问题,因为不会有对象要通过!相反,空引用由传递值的方式与任何其他引用相同。如果这个简短的解释让您感到困惑,那么您可能想看看我的文章“在C#中传递参数”(http://mng.bz/otVt),其中包含更多内容细节这些神话并不是唯一的神话。拳击和拆箱是他们的我会努力澄清这一误解。

参考:Jon Skeet的C#深度第三版

除了运行时直接使用的值类型和其他用于PInvoke的值类型之外,您只能在两种情况下使用值类型。

当您需要复制语义时。当您需要自动初始化时,通常在这些类型的数组中。

.NET支持值类型和引用类型(在Java中,只能定义引用类型)。引用类型的实例在托管堆中分配,并且在没有未完成的引用时被垃圾收集。另一方面,值类型的实例是在堆栈中分配的,因此一旦其作用域结束,分配的内存就会被回收。当然,值类型通过值传递,引用类型通过引用传递。除了System.String之外,所有C#原语数据类型都是值类型。

何时在类上使用结构,

在C#中,结构是值类型,类是引用类型。您可以使用enum关键字和struct关键字在C#中创建值类型。使用值类型而不是引用类型将导致托管堆上的对象减少,从而减少垃圾收集器(GC)的负载,减少GC周期,从而提高性能。然而,价值类型也有其缺点。传递一个大结构肯定比传递一个引用成本更高,这是一个明显的问题。另一个问题是与装箱/拆箱相关的开销。如果您想知道装箱/拆箱是什么意思,请按照以下链接了解装箱和拆箱的详细说明。除了性能之外,有时您只需要类型具有值语义,如果引用类型是您的全部,那么这将很难实现(或者很难看)。当您需要复制语义或需要自动初始化时(通常在这些类型的数组中),您应该只使用值类型。

简单地说,如果:

您的对象财产/字段不需要更改。我的意思是你只想给它们一个初始值,然后读它们。对象中的财产和字段是值类型,它们并没有那么大。

如果是这种情况,您可以利用结构来获得更好的性能和优化的内存分配,因为它们只使用堆栈,而不是同时使用堆栈和堆(在类中)

这是一条基本规则。

如果所有成员字段都是值类型,则创建一个结构。如果任何一个成员字段是引用类型,请创建一个类。这是因为引用类型字段无论如何都需要堆分配。

Exmaples公司

public struct MyPoint 
{
    public int X; // Value Type
    public int Y; // Value Type
}

public class MyPointWithName 
{
    public int X; // Value Type
    public int Y; // Value Type
    public string Name; // Reference Type
}