I was reading C# in Depth (3rd edition) and in chapter 13, in a section which talks about inclusion of covariant and contravariant type parameters in c# 4, this claim is made:
The parameter for List.AddRange is of type IEnumerable<T>, so in this case you’re treating each list as an IEnumerable <IShape>—something that wouldn’t have been possible before. AddRange could have been written as a generic method with its own type parameter, but it wasn’t—doing this would’ve made some optimizations hard or impossible.
Could anyone provide some justification for this claim? It is not obvious why it is true for me.
I would guess it was not written as void AddRange<T>(IEnumerable<T> items)
is because of optimisations it does when the IEnumerable<T>
is an ICollection<T>
. When the IEnumerable<T>
is an ICollection<T>
, AddRange internally calls ICollection<T>.CopyTo
, the first parameter of which is T[]
. (Note that the underlying storage mechanism for a List<T>
is a T[]
).
An array of a base type is not the same as an array of a derived type, so you cannot do this for example:
object[] objs = new object[4];
var collection = (new string[4]) as ICollection<string>;
collection.CopyTo(objs,0); //Cannot convert object[] to string[]
This is the optimisation that would be "impossible".
You can view the source here: https://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,79de3e39e69a4811
It seems like AddRange
should check for T[]
and List<T>
, and do an Array.Copy
in those cases, but -100, I guess. You might be somewhat surprised by what Array.ToArray()
doesn't do too.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With