在System.Data.Linq中,EntitySet<T>
使用了几个ItemList<T>
结构,如下所示:
internal struct ItemList<T> where T : class
{
private T[] items;
private int count;
...(methods)...
}
(花了我比发现它更长的时间 - 无法理解为什么EntitySet<T>
中的实体字段没有抛出空引用异常!)
我的问题是,将它作为一个类的结构实现它有什么好处?
答案 0 :(得分:34)
让我们假设您要将ItemList<T>
存储在数组中。
分配值类型数组(struct
)将数据存储在数组中。另一方面,如果ItemList<T>
是引用类型(class
),则只有对ItemList<T>
个对象的引用才会存储在数组中。实际的ItemList<T>
对象将在堆上分配。到达ItemList<T>
实例需要额外的间接级别,因为它只是一个与长度相结合的数组,使用值类型会更有效。
在检查EntitySet<T>
的代码后,我可以看到没有涉及数组。但是,EntitySet<T>
仍包含两个ItemList<T>
个实例。由于ItemList<T>
是struct
,因此这些实例的存储分配在EntitySet<T>
对象内。如果使用了class
,EntitySet<T>
将包含指向单独分配的EntitySet<T>
个对象的引用。
在大多数情况下,使用其中一个或另一个之间的性能差异可能并不明显,但开发人员可能认为他希望将数组和紧耦合计数视为单个值,因为它似乎是最好的事情
答案 1 :(得分:9)
对于像ItemList<T>
这样的小型关键内部数据结构,我们通常可以选择使用引用类型或值类型。如果代码写得很好,从一个代码切换到另一个代码是一个微不足道的变化。
我们可以推测一个值类型可以避免堆分配,而引用类型可以避免结构复制,因此它不会立即清楚,因为它在很大程度上取决于它的使用方式。
找出哪个更好的最好方法是来衡量。无论哪个更快,都是明显的赢家。我确信他们做了基准测试,struct
更快了。在你完成这几次之后,你的直觉非常好,基准测试只是证实你的选择是正确的。
答案 2 :(得分:6)
答案 3 :(得分:5)
使用结构实际上只有两个原因,那就是获取值类型语义,或者获得更好的性能。
由于struct包含一个数组,因此值类型语义不能正常工作。复制结构时,您将获得count
的副本,但只获得对数组的引用的副本,而不是数组中项目的副本。因此,每当复制结构时都必须特别小心,这样就不会得到不一致的实例。
因此,唯一剩下的正当理由是表现。每个引用类型实例都有一个很小的开销,所以如果你有很多它们,可能会有明显的性能提升。
这种结构的一个很好的特性是你可以创建它们的数组,并且你得到一个空列表数组而不必初始化每个列表:
ItemList<string>[] = new ItemList<string>[42];
由于数组中的项是零填充的,count
成员将为零,items
成员将为null。
答案 4 :(得分:2)
纯粹猜测:
由于对象相当小(只有两个成员变量),因此将struct
作为ValueType
进行传递是一个很好的选择。
另外,正如@Martin Liversage指出的那样,通过成为ValueType
,它可以更有效地存储在更大的数据结构中(例如作为数组中的项目),而不会产生单个对象和参考它。