什么时候应该在C#中使用结构而不是类?我的概念模型是,当项只是值类型的集合时,使用结构。一种将它们逻辑地结合在一起的方法。
我在这里遇到了这些规则:
结构应表示单个价值结构应具有内存占用空间小于16字节。结构不应在之后更改创造
这些规则有效吗?结构在语义上意味着什么?
什么时候应该在C#中使用结构而不是类?我的概念模型是,当项只是值类型的集合时,使用结构。一种将它们逻辑地结合在一起的方法。
我在这里遇到了这些规则:
结构应表示单个价值结构应具有内存占用空间小于16字节。结构不应在之后更改创造
这些规则有效吗?结构在语义上意味着什么?
当前回答
我不同意原帖子中给出的规则。以下是我的规则:
当存储在数组中时,可以使用结构来提高性能。(另请参见结构何时是答案?)在向C/C传递结构化数据的代码中需要它们++除非需要,否则不要使用结构:它们的行为与赋值下的“正常对象”(引用类型)不同当作为参数传递时,这可能导致意外行为;如果查看代码的人不知道他们正在处理一个结构。它们不能被继承。将结构作为参数传递比类更昂贵。
其他回答
.NET支持值类型和引用类型(在Java中,只能定义引用类型)。引用类型的实例在托管堆中分配,并且在没有未完成的引用时被垃圾收集。另一方面,值类型的实例是在堆栈中分配的,因此一旦其作用域结束,分配的内存就会被回收。当然,值类型通过值传递,引用类型通过引用传递。除了System.String之外,所有C#原语数据类型都是值类型。
何时在类上使用结构,
在C#中,结构是值类型,类是引用类型。您可以使用enum关键字和struct关键字在C#中创建值类型。使用值类型而不是引用类型将导致托管堆上的对象减少,从而减少垃圾收集器(GC)的负载,减少GC周期,从而提高性能。然而,价值类型也有其缺点。传递一个大结构肯定比传递一个引用成本更高,这是一个明显的问题。另一个问题是与装箱/拆箱相关的开销。如果您想知道装箱/拆箱是什么意思,请按照以下链接了解装箱和拆箱的详细说明。除了性能之外,有时您只需要类型具有值语义,如果引用类型是您的全部,那么这将很难实现(或者很难看)。当您需要复制语义或需要自动初始化时(通常在这些类型的数组中),您应该只使用值类型。
当您需要值语义而不是引用语义时,请使用结构。
如果需要引用语义,则需要类而不是结构。
除了常见的性能差异之外,让我再补充一个方面,那就是默认值的使用意图。
如果其字段的默认值不表示建模概念的合理默认值,请不要使用结构。
Eg.
即使所有字段都设置为默认值,“颜色”或“点”也有意义。RGB 0,0,0是一种非常好的颜色,(0,0)作为2D中的点也是如此。但是Address或PersonName没有合理的默认值。我的意思是,你能理解FirstName=null和LastName=null的PersonName吗?
如果你用一个类实现了一个概念,那么你可以强制执行某些不变量,例如一个人必须有名字和姓氏。但对于结构,总是可以创建一个实例,将其所有字段设置为默认值。
因此,当对没有合理默认值的概念进行建模时,更喜欢类。类的用户会明白null意味着没有指定PersonName,但如果您给他们一个PersonName结构实例,并将其所有财产设置为null,他们会感到困惑。
(通常的免责声明:性能考虑可能会凌驾于此建议之上。如果您有性能问题,请在决定解决方案之前进行衡量。试试BenchmarkDotNet,这很好!)
我使用结构来打包或解包任何类型的二进制通信格式。这包括读取或写入磁盘、DirectX顶点列表、网络协议或处理加密/压缩数据。
在这方面,你列出的三条准则对我来说并不有用。当我需要以特殊顺序写出400字节的内容时,我将定义一个400字节的结构,并用它应该具有的任何不相关的值填充它,我将以当时最合理的方式设置它。(好吧,四百字节会很奇怪——但当我以写Excel文件为生的时候,我处理的是多达四十字节的结构,因为这就是一些BIFF记录的大小。)
无论何时:
不需要多态性,want值语义,以及希望避免堆分配和相关的垃圾收集开销。
然而,需要注意的是,结构(任意大)传递比类引用(通常是一个机器字)更昂贵,因此类在实践中可能会更快。