C# 为什么要将其实现为结构?

C# 为什么要将其实现为结构?,c#,linq,struct,C#,Linq,Struct,在System.Data.Linq中,EntitySet使用两个ItemList结构,如下所示: internal struct ItemList<T> where T : class { private T[] items; private int count; ...(methods)... } 内部结构项列表,其中T:class { 私人物品; 私人整数计数; …(方法)。。。 } (我花了更长的时间才发现这一点-无法理解为什么Entity

在System.Data.Linq中,
EntitySet
使用两个
ItemList
结构,如下所示:

 internal struct ItemList<T> where T : class
  {
    private T[] items;
    private int count;
    ...(methods)...
  }
内部结构项列表,其中T:class
{
私人物品;
私人整数计数;
…(方法)。。。
}
(我花了更长的时间才发现这一点-无法理解为什么
EntitySet
中的entities字段没有抛出空引用异常!)


我的问题是,将其作为类上的结构实现有什么好处?

这里仅作推测:

由于对象相当小(只有两个成员变量),因此可以将其设置为
结构
,以允许将其作为
值类型
传递


此外,正如@Martin Liversage所指出的,作为
值类型,它可以更高效地存储在更大的数据结构中(例如,作为数组中的一个项),而无需拥有单个对象和对其引用的开销。

新变量和原始变量 因此,变量包含两个 相同数据的单独副本。 对一个副本所做的更改不会影响另一个副本


只是想一想,不要对我太苛刻:)

让我们假设您想将
项目列表
存储在一个数组中

分配一个值类型数组(
struct
)将把数据存储在数组中。另一方面,如果
ItemList
是引用类型(
class
),则数组中只存储对
ItemList
对象的引用。实际上,
ItemList
对象将在堆上分配。要到达
ItemList
实例,需要额外级别的间接寻址,因为它只是一个数组,结合了长度,所以使用值类型更有效

检查完
EntitySet
的代码后,我可以看到没有涉及任何数组。但是,
EntitySet
仍然包含两个
ItemList
实例。由于
ItemList
是一个
struct
结构,这些实例的存储在
EntitySet
对象中分配。如果使用
,则
实体集
将包含指向单独分配的
实体集
对象的引用


在大多数情况下,使用一个或另一个之间的性能差异可能不明显,但可能开发人员决定将数组和紧密耦合的计数作为一个值来处理,因为这似乎是最好的选择。

对于小型关键内部数据结构,如
ItemList
,我们通常可以选择使用引用类型或值类型。如果代码编写得很好,那么从一个代码切换到另一个代码只是一个微不足道的变化

我们可以推测,值类型可以避免堆分配,引用类型可以避免结构复制,因此这两种方法都不清楚,因为它在很大程度上取决于如何使用它


找出哪一个更好的最好方法是测量它。谁跑得快谁就明显获胜。我确信他们做了他们的基准测试,
struct
更快。在您这样做了几次之后,您的直觉是非常好的,基准测试只是确认了您的选择是正确的。

使用结构实际上只有两个原因,那就是要么获得值类型语义,要么获得更好的性能

由于结构包含数组,值类型语义无法正常工作。当您复制结构时,您会得到一个
计数的副本,但您只会得到一个数组引用的副本,而不是数组中项目的副本。因此,无论何时复制结构,都必须特别小心,以免得到不一致的实例

因此,剩下的唯一有效原因是性能。每个引用类型实例都有一个小的开销,因此如果您有很多引用类型实例,那么可能会有明显的性能提升

这种结构的一个妙处是,您可以创建一个空列表数组,而无需初始化每个列表即可获得一个空列表数组:

ItemList<string>[] = new ItemList<string>[42];
ItemList[]=newitemlist[42];

由于数组中的项目是零填充的,
count
成员将为零,
items
成员将为空。

注意:呼叫医生Skeet,我重复:呼叫医生Skeet@sehe-可怜的家伙会醒过来的。@manojlds-如果这是正常的一天,他会在工作,带着“一些如此的存在”@Kobi-我以为他在英国?不管怎样,在飞碟比赛中,我总是错的!也许在这种情况下没有什么好处,但它是在开发人员的突发奇想下完成的,因此保持不变,因为没有改变的优势或紧迫理由。@Jen:好的,但是作为ValueType传递它有什么好处?嗯,一个问题:因为T是一个类,这个结构可以作为ValueType传递吗?我想知道,真的……我相信结构也会在堆中(不是所有的结构都在堆栈上)再次推测,但我认为
ItemList
的作者打算通过组合而不是引用将其包含到其他对象中。而@Simon,是的,它很可能会在某个时候进入堆中。存储最终由VM决定。作者是Microsoft-这是他们的Linq代码。它是通过合成来使用的,但是它被标记为内部的,并且只在EntitySet类中使用。这一点很好。但是,当一个计数与一个数组相关联时,计数很可能会跟踪数组中有多少项正在使用。如果复制此结构并修改新结构中的计数,则原始结构仍将引用同一数组,但计数不会更新。因此,对于结构的这种特殊使用,我非常确定开发人员必须非常小心,不要复制结构