C# 为什么要将其实现为结构?
在System.Data.Linq中,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
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类中使用。这一点很好。但是,当一个计数与一个数组相关联时,计数很可能会跟踪数组中有多少项正在使用。如果复制此结构并修改新结构中的计数,则原始结构仍将引用同一数组,但计数不会更新。因此,对于结构的这种特殊使用,我非常确定开发人员必须非常小心,不要复制结构