根据我的阅读,出于性能原因,某些集合的枚举器类型被设计为可变结构而不是引用类型。List.Enumerator 是最著名的。
我正在研究一些使用数组的旧代码,并惊讶地发现 C# 数组返回类型 SZGenericArrayEnumerator 作为它们的通用枚举类型,这是一个引用类型。
我想知道是否有人知道为什么当许多其他性能关键集合使用可变结构时,Array 的通用迭代器被实现为引用类型。
根据我的阅读,出于性能原因,某些集合的枚举器类型被设计为可变结构而不是引用类型。List.Enumerator 是最著名的。
我正在研究一些使用数组的旧代码,并惊讶地发现 C# 数组返回类型 SZGenericArrayEnumerator 作为它们的通用枚举类型,这是一个引用类型。
我想知道是否有人知道为什么当许多其他性能关键集合使用可变结构时,Array 的通用迭代器被实现为引用类型。
根据我的阅读,出于性能原因,某些集合的枚举器类型被设计为可变结构而不是引用类型。
好问题。
首先,你是对的。虽然一般来说,可变值类型是一种不好的代码气味,但在这种情况下它们是合理的:
我想知道是否有人知道为什么当许多其他性能关键集合使用可变结构时,Array 的通用迭代器被实现为引用类型。
因为如果你是那种关心枚举数组的性能的人,那么你为什么要首先使用枚举器呢?看在上帝的份上,这是一个阵列;只需编写一个for
循环,像普通人一样迭代其指标,并且从不分配枚举数。(或者一个循环;如果 C# 编译器知道循环集合是一个数组,它foreach
会将循环重写foreach
为等效循环。)for
首先从数组中获取枚举器的唯一原因是,如果您将它传递给采用 的方法IEnumerator<T>
,在这种情况下,如果枚举器是一个结构,那么无论如何您都将对其进行装箱。为什么要承担制作值类型然后装箱的费用?只需将其作为参考类型即可。
数组在 C# 编译器中得到一些特殊处理。当您foreach
在它们上使用时,编译器会将其转换为for
循环。struct
因此,使用枚举器没有性能优势。
List<T>
另一方面是一个没有任何特殊处理的普通类,因此使用结构可以获得更好的性能。