16

We know System.Array is a abstract class and whatever DataType[] we use runtime creates some concrete implementation for us somehow (vague though).

Consider the following snippet.

int[] someInts = { 1, 2, 3, 4 };
IList<int> collection = someInts;
collection.Clear();

collection.Clear() throws NotSupportedException, Nothing surprising there. When I check to see the "StackTrace" am surprised to see it shows some strange "Type" SZArrayHelper at top of the call stack.

StackTrace:

   at System.SZArrayHelper.Clear[T]()//Note this.. How???
   at TestApplication.Program.Main()

How come that is possible? am calling Clear() method on int[] but then how does the call go to SZArrayHelper.Clear. note that Clear is an instance method in SZArrayHelper defined as below.

private void Clear<T>()
{
    throw new NotSupportedException(Environment.GetResourceString("NotSupported_ReadOnlyCollection"));
}

Who creates the instance of "SZArrayHelper" and also note that Clear method is private. Am very confused about what's happening. If at all an instance of "SZArrayHelper" is created and Clear is called then that helper method doing this call should come in the "StackTrace". But that is not the case here.

Can somebody explain what's happening behind the scenes?

Note:

  1. int[] is just an example, you can pretty much simulate it with any type of array, and not only Clear method Add, Contains etc possesses same behavior.

  2. I tried to debug using reflector addin, which gave me the same results. The debugger shows a direct call to SZArrayHelper.Clear<T>().

  3. Google led me to this .NET Arrays, IList, Generic Algorithms, and what about STL?. That helped to understand the kind of magic that is going on behind the scenes, but some mystery still remains.

David Klempfner
  • 8,700
  • 20
  • 73
  • 153
Sriram Sakthivel
  • 72,067
  • 7
  • 111
  • 189
  • Am not sure whether c# tag is relevant. I just added it since I tried it with c# and many folks would be monitoring it. – Sriram Sakthivel Nov 11 '13 at 19:45
  • 3
    Private class methods can implement public interface methods. – rninty Nov 11 '13 at 19:45
  • @rninty My question is not that. and private class can implement interfaces but methods can't be private. That is not the case here – Sriram Sakthivel Nov 11 '13 at 19:47
  • 6
    This has always annoyed me that the array type implements `IList` - since it can't do the basic stuff that a list can, like adding items, removing items, clearing itself, etc. I'm sure there's a reason it was done that way, but it's caught me a few times. – Joe Enos Nov 11 '13 at 19:48
  • 2
    @JoeEnos - Object of `IList` should be expected to behave this way when it returns `IsReadOnly=true` (like arrays - `((IList)(new int[3])).IsReadOnly == true` ). – Alexei Levenkov Nov 11 '13 at 19:51
  • 1
    `Array` implement `IList` at runtime. Apparently this implemenation calls `SZArrayHelper.Clear()` – Magnus Nov 11 '13 at 19:51
  • @Magnus If so, where is the method that calls `SZArrayHelper.Clear()` in stacktrace? That is missing. – Sriram Sakthivel Nov 11 '13 at 19:53
  • 11
    Arrays are basically voodoo. Because they pre-date generics, yet must allow on-the-fly type-creation (even in .NET 1.0), they are implemented using tricks, hacks, and sleight of hand. I *think* what you are seeing is basically the implementation details of the trickery. It is all very interesting, but sometimes it is best to stay outside the curtain and enjoy the show. Ignorance is bliss ;p – Marc Gravell Nov 11 '13 at 19:55
  • 1
    @JoeEnos I agree. This is just one of many dreadful abuses of the Liskov Substitution Principle - that lies at the heart of all good SOLID designs- the MS is guilty of. There must be a reason it was done this way, but I can't think of a *good* reason. There again MS have committed the same sins with the new immutable collections classes and the excuse there was nothing more than bowing pressure from developers who didn't know what they were talking about sadly. – David Arno Nov 11 '13 at 19:56
  • 1
    @DavidArno I'd be interested in more details on these "same sins". This probably isn't the right place, though. – Marc Gravell Nov 11 '13 at 19:57
  • @MarcGravell you're right. on the other hand if somebody can answer me then I'd learn something new. Am curious and confused too. :) – Sriram Sakthivel Nov 11 '13 at 19:59
  • The [comments](http://stackoverflow.com/a/15341925/468973) for the array class might help to shed some light on the subject. – Magnus Nov 11 '13 at 20:07
  • 1
    @MarcGravell I'm talking of things like ReadOnlyCollection implementing IList and throwing a not implemented exception when eg Clear() is called, rather than having IList<> extend IReadOnlyList<> and have ReadOnlyCollection<> implement the latter only. That would have been employing the SOLID principle. – David Arno Nov 11 '13 at 20:07
  • @DavidArno That would mean all lists would be `IReadOnlyList<>`. Not sure I like that. – Magnus Nov 11 '13 at 20:10
  • @Magnus Not so. It would simply mean all lists would implement the IReadOnlyList contract and even a mutable list could be supplied to a method that required a IReadOnlyList instance. In reality, I personally would have made IList<> an immutable contract and extended it via a IMutableList<> interface. But that's largely semantics. The Liskov substitution principle would be upheld either way. – David Arno Nov 11 '13 at 20:17
  • @DavidArno They would all _implement_ `IReadOnlyList<>` which does not feel right. But I see your point. – Magnus Nov 11 '13 at 20:22
  • @DavidArno without supporting the legacy interfaces, they would be of limited use; too much code is read-only by for historic reasons uses `IList[]`. Fortunately, there is `IList.ReadOnly` which code *can check* – Marc Gravell Nov 11 '13 at 21:05
  • @MarcGravell It was those legacy interfaces that I was criticising. Liskov formulated the idea in '87, long before .NET was conceived, thus there is no real excuse for those botched interfaces. – David Arno Nov 11 '13 at 21:15
  • Related: ["Arrays and the CLR - a Very Special Relationship"](http://mattwarren.org/2017/05/08/Arrays-and-the-CLR-a-Very-Special-Relationship/) links back to this question, specifically @MarcGravell's comment about array voodoo. – Nat May 10 '17 at 00:02

1 Answers1

10

You're not seeing any call to that method, because you're invoking it yourself, as weird as that may sound. SZArrayHelper is a CLR wrapper around an array, that implements the IList<T> interface, kinda like the adapter pattern.

From this perspective, it makes sense that collection.Clear invokes SZArrayHelper.Clear directly.

Hans Passant explains this very well here: https://stackoverflow.com/a/11164210/857807

Community
  • 1
  • 1
dcastro
  • 66,540
  • 21
  • 145
  • 155