The comments provided in the source code for IList, IEnumerable and ICollection says
Note that
T[] : IList<T>
, and we want to ensure that if you useIList<YourValueType>
, we ensure aYourValueType[]
can be used without jitting. Hence theTypeDependencyAttribute
onSZArrayHelper
. This is a special hack internally though - see VM\compile.cpp.
Why does IList<T>
contain a dependency on SZArrayHelper
?. I understand that SZArrayHelper
is a CLR wrapper around an array that implements the IList<T>
interface but I do not get the full picture of why these two are tied together.
And how does it ensure YourValueType[]
can be used without jitting.?
It's a hack in the JIT, as noted in your quote. When the VM finds that there's a TypeDependency
on SZArrayHelper
, it treats the class differently, allowing more efficient code to be used.
Looking at the relevant code in the VM (note that I'm using an older, public version here - not the actual .NET VM):
A call to an array thru IList (or IEnumerable or ICollection) has to be handled specially. These interfaces are "magic" (mostly due to working set concerned - they are created on demand internally even though semantically, these are static interfaces.)
Arrays are a bit of a hack in .NET in the first place. When the generic interfaces were added, this posed a bit of a problem - for example, int[]
is an Array
, but it is also a special type, and array of int; this allowed arrays to be generic before real generic types were added.
Now, let's see a concrete example. You have an int[]
, and you want to use it in LINQ. Since int[]
implements IEnumerable<int>
, it gives you the full power of LINQ out of the box, and you can write something like this:
var positiveNumbers = numbers.Where(i => i > 0);
From C#'s point of view, there is no problem. However, from the point of the internals of the VM, this is a big problem, because int[]
doesn't actually implement IEnumerable<int>
! Even after introducing generics to .NET (and C#), arrays are still handled the old way.
The hack is to use SZArrayHelper
to handle any of those generic methods. So, for example, Where
calls GetEnumerator
internally on the IEnumerable<int>
. The VM finds out that you're trying to call GetEnumerator
on an array, and instead of virtually dispatching GetEnumerator
on the array instance, it redirects the call to SZArrayHelper.GetEnumerator<int>()
.
This is a huge hack - if you look at the reference code for SZArrayHelper
, you'll find tons of warnings - for example, the GetEnumerator<int>
method is an instance method, but it's this
argument is actually the array (e.g. int[]
), not SZArrayHelper
.
But it allows us to treat arrays as if they did actually implement all those generic interfaces - even though they don't :)
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