The List<T> code in question is:
#pragma warning disable CA1825, IDE0300 // avoid the extra generic instantiation for Array.Empty<T>()
private static readonly T[] s_emptyArray = new T[0];
#pragma warning restore CA1825, IDE0300
This cached empty array is used, for instance, when List<T>.ToArray()
is called and the list is empty.
Now, why does this custom caching of an empty array exist, and why is Array.Empty<T>()
seen as an "extra generic instantiation" that needs to be avoided? Wouldn't it be the case that, during runtime, if Array.Empty<T>()
is used elsewhere, s_emptyArray
would become the "extra" instantiation because there would now be two cached empty instances? Or is this about avoiding some performance impact arising from Array.Empty<T>()
, which delegates to the static class EmptyArray<T>
that contains the actual empty array? Is the performance impact of this generic access (I wouldn't quite call it "instantiation," as the code comment does) significant enough to justify having a custom cached empty array and potentially two instances of empty arrays during runtime? Should we also consider creating and using our own cached empty arrays in high-performance scenarios?
This not only avoids the generic call to Array.Empty<T>()
, but also creating a new generic type EmptyArray<T>
for every List<T>
. Since every new generic type introduced at runtime comes with a small overhead (JIT and memory usage) this can accumulate, because List'1
is extremely widely used for many different T
's.