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

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

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

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


当前回答

我刚刚在处理Windows Communication Foundation[WCF]命名管道,我注意到使用Structs确实有意义,以确保数据交换是值类型而不是引用类型。

其他回答

类最适合将复杂的操作和数据分组在一起这将在整个项目中发生变化;结构是更好的选择大多数情况下保持不变的简单对象和数据。除了它们的用途之外,它们在一个键上有根本的不同即变量之间传递或分配的方式。类是引用类型,这意味着它们由参考结构是值类型,这意味着它们是由价值

小心使用类。如果您有一些引用相同内存的游戏对象,修改其中一个将修改其他对象。

创建结构对象时,其所有数据都存储在没有引用或连接到其内存的对应变量地方这使得结构对于创建需要快速高效地复制,同时保留独立的身份。

ExampleStruct struct1= new ExampleStruct()
ExampleStruct struct2= struct1

修改结构2不会影响结构1。

基本上,创建结构是为了提高性能。但是,由于涉及到所有的复制,有时结构可能会更慢。如果结构有很多需要复制的变量,那么将其转换为类并传递引用可能会更快如果您有一个结构数组,那么数组本身就是堆上的一个对象,结构值包含在数组中。所以垃圾收集器只有一个对象需要考虑。如果数组超出范围,垃圾收集器可以在一个步骤中释放数组中的所有结构。如果代码的任何其他部分正在使用此数组中的结构,由于结构被复制,因此我们可以安全地释放数组本身及其内容。如果您有一个对象数组,那么数组本身和数组中的每个对象都是堆上的独立对象。每个对象都可以存储在堆的完全不同的部分,而代码的另一部分可能会引用这些对象。因此,当我们的数组超出范围时,我们无法立即释放数组。因为垃圾收集器必须单独考虑每个对象,并确保在取消分配之前没有对每个对象的引用。

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

何时在类上使用结构,

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

除了“它是一个值”的答案之外,使用结构的一个特定场景是当您知道有一组数据会导致垃圾收集问题,并且您有很多对象时。例如,Person实例的大列表/数组。这里的自然隐喻是一个类,但如果您有大量长寿的Person实例,它们可能会阻塞GEN-2并导致GC暂停。如果场景允许,这里的一种潜在方法是使用Person结构的数组(而不是列表),即Person[]。现在,在GEN-2中没有数百万个对象,而是在LOH上有一个块(我假设这里没有字符串等-即没有任何引用的纯值)。这对GC的影响很小。

处理这些数据是很困难的,因为数据对于一个结构来说可能太大了,而且您不想一直复制胖值。然而,直接在数组中访问它不会复制结构-它是在适当的位置(与列表索引器不同,它会复制)。这意味着大量的索引工作:

int index = ...
int id = peopleArray[index].Id;

请注意,保持值本身不可变将有助于此。对于更复杂的逻辑,请使用带有by-ref参数的方法:

void Foo(ref Person person) {...}
...
Foo(ref peopleArray[index]);

同样,这是正确的-我们没有复制值。

在非常具体的情况下,这种策略可能非常成功;然而,这是一个相当先进的scernario,只有当你知道自己在做什么和为什么时,才应该尝试。这里的默认值是类。

不,我不完全同意这些规则。它们是考虑性能和标准化的良好指南,但不是根据可能性。

正如你在回答中看到的,有很多创造性的方法来使用它们。因此,这些指导原则需要做到这一点,始终是为了性能和效率。

在本例中,我使用类以更大的形式表示真实世界的对象,使用结构来表示具有更精确用途的较小对象。你说的是,“一个更具凝聚力的整体”。类将是更多面向对象的元素,而结构可以具有这些特性,尽管规模较小。IMO。

我在Treeview和Listview标签中经常使用它们,在这些标签中可以非常快速地访问常见的静态属性。我一直在努力以另一种方式获取这些信息。例如,在我的数据库应用程序中,我使用Treeview,其中包含表、SP、函数或任何其他对象。我创建并填充我的结构,将其放入标记中,将其拉出,获取所选内容的数据等等。我不会在课堂上这样做!

我确实会尽量缩小它们,在单实例情况下使用它们,并防止它们发生变化。注意内存、分配和性能是明智的。测试是非常必要的。

我认为一个好的第一近似值是“从不”。

我认为一个好的二次近似是“从不”。

如果你渴望表现,那么考虑一下,但始终要衡量。