Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why would making List<T>.AddRange method a generic one be bad for performance?

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.

like image 241
user1242967 Avatar asked Aug 08 '18 10:08

user1242967


1 Answers

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.

like image 192
MineR Avatar answered Sep 28 '22 12:09

MineR