为什么这是一个结构实现?

在System.Data.Linq中, EntitySet<T>使用了几个ItemList<T>结构,如下所示:

  internal struct ItemList<T> where T : class { private T[] items; private int count; ...(methods)... } 

(花了我更多的时间来发现这一点 – 无法理解为什么EntitySet<T>的实体字段没有抛出空引用exception!)

我的问题是作为一个类的结构实现这个好处是什么?

让我们假设你想将ItemList<T>存储在一个数组中。

分配值types的数组( struct )将数据存储在数组中。 另一方面,如果ItemList<T>是一个引用types( class ),那么只有对ItemList<T>对象的引用才会被存储在数组中。 实际的ItemList<T>对象将被分配在堆上。 要达到ItemList<T>实例需要额外的间接级别,因为它只是一个数组和长度的组合,所以使用值types更为有效。

结构与类

在检查EntitySet<T>的代码后,我可以看到没有涉及数组。 但是,一个EntitySet<T>仍然包含两个ItemList<T>实例。 由于ItemList<T>是一个struct所以这些实例的存储都是在EntitySet<T>对象内部分配的。 如果使用class而不是EntitySet<T>将包含指向单独分配的EntitySet<T>对象的引用。

在大多数情况下,使用这两者之间的性能差异可能并不明显,但开发人员可能决定将数组和紧密耦合的计数视为单个值,因为这似乎是最好的做法。

对于小的关键内部数据结构(如ItemList<T> ,我们经常可以select使用引用types还是值types。 如果代码写得很好,从一个切换到另一个是一个微不足道的变化。

我们可以推测,一个值types避免了堆的分配,而一个引用types避免了结构体的拷贝,所以它不是立即清楚的,因为它非常依赖于它的使用方式。

找出哪一个更好的最好方法就是测量它 。 无论哪个更快是明确的赢家。 我确定他们的基准testing和struct更快。 在你做了几次这样的事后,你的直觉是相当不错的,基准只是证实你的select是正确的。

也许它的重要性,从这里引用结构

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

只是在想,不要硬判断我:)

实际上只有两个理由使用结构,那就是获得值types的语义,或者为了获得更好的性能。

由于结构体包含数组,因此值types语义不能正常工作。 当你复制结构时,你得到了一个count的副本,但是你只能得到一个数组引用的副本,而不是数组中的项目的副本。 因此,只要结构被复制,就不得不使用特殊的注意,这样就不会出现不一致的实例。

所以,唯一剩下的正当理由就是表演。 每个引用types实例都有一个小的开销,所以如果你有很多这样的实例,那么可能会有一个明显的性能提升。

这种结构的一个奇妙的特点是你可以创build它们的一个数组,并且你得到一个空列表的数组而不必初始化每个列表:

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

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

纯粹在这里推测:

由于该对象相当小(只有两个成员variables),因此将它作为一个允许以ValueTypeforms传递的struct是一个很好的select。

此外,正如@Martin Liversage所指出的那样,作为一个ValueType它可以更有效地存储在更大的数据结构中(例如作为数组中的一个项目),而不需要单独的对象和引用的开销。