什么时候应该在C#中使用结构而不是类?我的概念模型是,当项只是值类型的集合时,使用结构。一种将它们逻辑地结合在一起的方法。
我在这里遇到了这些规则:
结构应表示单个价值结构应具有内存占用空间小于16字节。结构不应在之后更改创造
这些规则有效吗?结构在语义上意味着什么?
什么时候应该在C#中使用结构而不是类?我的概念模型是,当项只是值类型的集合时,使用结构。一种将它们逻辑地结合在一起的方法。
我在这里遇到了这些规则:
结构应表示单个价值结构应具有内存占用空间小于16字节。结构不应在之后更改创造
这些规则有效吗?结构在语义上意味着什么?
当前回答
以下是在Microsoft网站上定义的规则:
✔️ 如果类型的实例很小且通常很短,或者通常嵌入在其他对象中,请考虑定义结构而不是类。
❌ 避免定义结构,除非该类型具有以下所有特征:
它在逻辑上表示单个值,类似于原始类型(int、double等)。
它的实例大小小于16字节。
它是不可变的。
它不必经常装箱。
供进一步阅读
其他回答
我使用结构来打包或解包任何类型的二进制通信格式。这包括读取或写入磁盘、DirectX顶点列表、网络协议或处理加密/压缩数据。
在这方面,你列出的三条准则对我来说并不有用。当我需要以特殊顺序写出400字节的内容时,我将定义一个400字节的结构,并用它应该具有的任何不相关的值填充它,我将以当时最合理的方式设置它。(好吧,四百字节会很奇怪——但当我以写Excel文件为生的时候,我处理的是多达四十字节的结构,因为这就是一些BIFF记录的大小。)
结构在大多数方面类似于类/对象。结构可以包含函数、成员,并且可以继承。但C#中的结构仅用于数据保存。结构比类占用更少的RAM,并且垃圾收集器更容易收集。但当您在结构中使用函数时,编译器实际上采用的结构与类/对象非常相似,所以如果您想要使用函数,请使用类/对象。
当您需要值语义而不是引用语义时,请使用结构。
如果需要引用语义,则需要类而不是结构。
我的规则是
1、始终使用类;
如果有任何性能问题,我会根据@IAbstract提到的规则将一些类更改为结构,然后进行测试,看看这些更改是否可以提高性能。
C#或其他.net语言中的结构类型通常用于保存应该表现为固定大小的值组的内容。结构类型的一个有用方面是,可以通过修改保存结构类型实例的存储位置来修改该实例的字段,而不是以其他方式。可以以这样的方式对结构进行编码,即变异任何字段的唯一方法是构造一个完整的新实例,然后使用结构赋值通过用新实例中的值覆盖目标的所有字段来对其进行变异,但除非结构不提供创建其字段具有非默认值的实例的方法,如果结构本身存储在可变位置,则其所有字段都是可变的。
请注意,如果结构包含一个私有类类型字段,那么可以设计一个结构类型,使其基本上表现为类类型,并将其自身成员重定向到包装的类对象的成员。例如,PersonCollection可能提供财产SortedByName和SortedById,这两个属性都持有对PersonCollection的“不可变”引用(在其构造函数中设置),并通过调用creator.GetNameSortedEnumerator或creator.GetIdSortedEnumerator来实现GetEnumerater。此类结构的行为与对PersonCollection的引用非常相似,除了它们的GetEnumerator方法将绑定到PersonCollection中的不同方法。也可以有一个结构来包裹数组的一部分(例如,可以定义一个ArrayRange<T>结构,该结构将保存一个称为Arr的T[]、一个int Offset和一个int Length,以及一个索引属性,对于范围0到Length-1的索引idx,该属性将访问Arr[idx+Offset])。不幸的是,如果foo是这种结构的只读实例,当前的编译器版本将不允许像foo[3]+=4这样的操作;因为它们无法确定这些操作是否会尝试写入foo的字段。
也可以设计一个结构,使其行为类似于一个值类型,该值类型包含一个可变大小的集合(无论何时该结构都会被复制),但唯一可行的方法是确保该结构包含引用的对象不会暴露于任何可能使其发生变异的对象。例如,可以有一个类似数组的结构,它保存一个私有数组,其索引的“put”方法创建一个新数组,其内容与原始数组的内容相似,只有一个元素发生了更改。不幸的是,要使这种结构有效地执行可能有些困难。虽然有时结构语义可能很方便(例如,能够将类似数组的集合传递给例程,调用方和被调用方都知道外部代码不会修改集合,这可能比要求调用方和受调用方防御性地复制它们所提供的任何数据要好),类引用指向永远不会变异的对象的要求通常是一个相当严格的约束。