I’ve decompiled mscorlib library with ILSpy and noticed that List.Clear method uses Array.Clear(this._items, 0, this._size) internally.
// System.Collections.Generic.List<T>
/// <summary>Removes all elements from the <see cref="T:System.Collections.Generic.List`1" />.</summary>
public void Clear()
{
if (this._size > 0)
{
Array.Clear(this._items, 0, this._size);
this._size = 0;
}
this._version++;
}
Next, this Array.Clear method is setting up all array elements to zero, to false or to null, how it’s described. Also List.RemoveRange is using Array.Clear method too.
// System.Array
/// <summary>Sets a range of elements in the <see cref="T:System.Array" /> to zero, to false, or to null, depending on the element type.</summary>
/// <param name="array">The <see cref="T:System.Array" /> whose elements need to be cleared.</param>
/// <param name="index">The starting index of the range of elements to clear.</param>
/// <param name="length">The number of elements to clear.</param>
/// <exception cref="T:System.ArgumentNullException">
/// <paramref name="array" /> is null.</exception>
/// <exception cref="T:System.IndexOutOfRangeException">
/// <paramref name="index" /> is less than the lower bound of <paramref name="array" />.-or-<paramref name="length" /> is less than zero.-or-The sum of <paramref name="index" /> and <paramref name="length" /> is greater than the size of the <see cref="T:System.Array" />.</exception>
/// <filterpriority>1</filterpriority>
[ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success), SecuritySafeCritical]
[MethodImpl(MethodImplOptions.InternalCall)]
public static extern void Clear(Array array, int index, int length);
Is it possible to ignore Array.Clear(this._items, 0, this._size) method invoking in the first code listing for value types? I think it is not necessary. Am I right?
This question is actual not only for List, but for other generic collections too.
The garbage collector doesn’t know that elements beyond
_sizeare logically unreachable. All it sees is an array full of handles to objects, so it has to keep every one of those objects alive. For this reason, actually setting all the handles tonullis a necessary part of clearing the container, to allow the garbage collector to clean up the objects just removed from the list (if no other part of the program has a handle to them).For primitive types (
List<int>), this wouldn’t be necessary, but .NET doesn’t allow specializing generic types. Value types can contain handles, so the optimization wouldn’t be possible for them either, even if .NET had specialization.