在System.Data.Linq中,EntitySet<T>使用几个ItemList<T>结构,如下所示:
internal struct ItemList<T> where T : class
{
private T[] items;
private int count;
...(methods)...
}
Run Code Online (Sandbox Code Playgroud)
(花了我比它应该发现的更长的时间 - 无法理解为什么实体字段EntitySet<T>没有抛出空引用异常!)
我的问题是,将它作为一个类的结构实现它有什么好处?
Mar*_*age 34
让我们假设您要存储ItemList<T>在数组中.
分配值类型数组(struct)将数据存储在数组中.另一方面ItemList<T>,如果是引用类型(class),则只有ItemList<T>对象的引用才会存储在数组中.实际ItemList<T>对象将在堆上分配.到达ItemList<T>实例需要额外的间接级别,因为它只是一个与长度相结合的数组,使用值类型更有效.

在检查代码之后EntitySet<T>我可以看到没有涉及数组.但是,EntitySet<T>仍然包含两个ItemList<T>实例.由于ItemList<T>是一个struct用于这些实例的存储是在内部分配EntitySet<T>对象.如果使用了a class,那么EntitySet<T>将包含指向EntitySet<T>分别分配的对象的引用.
在大多数情况下,使用其中一个或另一个之间的性能差异可能并不明显,但开发人员可能决定将数组和紧耦合计数视为单个值,因为它似乎是最好的事情.
对于像ItemList<T>我这样的小型关键内部数据结构,我们通常可以选择使用引用类型或值类型.如果代码写得很好,从一个代码切换到另一个代码是一个微不足道的改变.
我们可以推测一个值类型可以避免堆分配,而引用类型可以避免结构复制,因此它不会立即清楚,因为它在很大程度上取决于它的使用方式.
找出哪个更好的最佳方法是测量它.无论哪个更快,都是明显的赢家.我确信他们做了基准测试并且struct速度更快.在你完成这几次之后,你的直觉非常好,基准测试只是证实你的选择是正确的.
使用结构实际上只有两个原因,那就是获取值类型语义,或者获得更好的性能.
由于struct包含一个数组,因此值类型语义不能很好地工作.复制结构时,您会获得该结构的副本count,但只能获得对数组的引用的副本,而不是数组中项目的副本.因此,每当复制结构时都必须特别小心,这样就不会得到不一致的实例.
因此,唯一剩下的有效理由是表现.每个引用类型实例都有一个小的开销,所以如果你有很多它们,那么可能会有明显的性能提升.
这种结构的一个很好的特性是你可以创建它们的数组,并且你得到一个空列表数组而不必初始化每个列表:
ItemList<string>[] = new ItemList<string>[42];
Run Code Online (Sandbox Code Playgroud)
由于数组中的项是零填充的,因此count成员将为零,items成员将为null.
这里纯粹是猜测:
由于该对象相当小(只有两个成员变量),因此它是一个很好的候选对象, struct可以将其作为 a 传递ValueType。
此外,正如 @Martin Liversage 指出的那样,通过成为 a,ValueType它可以更有效地存储在更大的数据结构中(例如作为数组中的项目),而无需拥有单个对象及其引用的开销。