为什么这是一个结构实现?
在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),因此将它作为一个允许以ValueType
forms传递的struct
是一个很好的select。
此外,正如@Martin Liversage所指出的那样,作为一个ValueType
它可以更有效地存储在更大的数据结构中(例如作为数组中的一个项目),而不需要单独的对象和引用的开销。