0

In a different question on stackoverflow somebody suggested to write an extension method for an array, but used the this IList<T> interface in the extension method. I commented it should be an array but he declined. I tested it, and of course, he's right... :)

Extension method:

public static void Fill<T>(this IList<T> array, T value)
{
    for(var i = 0; i < array.Count; i++) 
    {
        array[i] = value;
    }
}

Test code:

[Test] 
public void Stackoverflow()
{
    int[] arr = new int[] { 1,2,3,4};
    arr.Fill(2);
    Assert.AreEqual(2, arr[0]);
    Assert.AreEqual(2, arr[1]);
    Assert.AreEqual(2, arr[2]);
    Assert.AreEqual(2, arr[3]);
}

An array is not an IList<T>. Why does this even compile? Let alone, pass?!

bas
  • 13,550
  • 20
  • 69
  • 146

4 Answers4

6

Array doesn't implement IList<T>, but T[] does, thanks to some runtime magic. Arrays are a bit weird since should have been generic, but predate the generic system and thus use specialized hacks.

CodesInChaos
  • 106,488
  • 23
  • 218
  • 262
5

From section 12.1.2 of the C# 4 specification:

A one-dimensional array T[] implements the interface System.Collections.Generic.IList<T> and its base interfaces. Accordingly, there is an implicit conversion from T[] to IList<T> and its base interfaces.

It's worth noting that if you create a rectangular array or a one-dimensional array which has a lower bound other than zero, those do not implement IList<T>.

In the CLI, there are actually two terms: vector and array. A vector is a one-dimensional collection with a lower bound of zero, and is optimized to heck and back by the JIT. An array can have multiple dimensions and different lower bounds, and isn't subject to as thorough optimization.

A T[] in C# is always a vector. You can't cast an object which is a CLI-array to T[] - you end up with an exception like this:

Unhandled Exception: System.InvalidCastException: Unable to cast object of type
'System.String[*]' to type 'System.String[]'.
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 1
    That last sentence is interesting.. I did not know that! You are an incredible source of information. – Simon Whitehead Feb 17 '13 at 09:02
  • Other than the obvious answer of "Because he is Jon Skeet".. how do you find all of this information? I love all of these implementation details and other than the book "Pro .NET Performance" I've found it hard to come across this level of detail. – Simon Whitehead Feb 17 '13 at 09:13
  • well he wrote the book "C# in Depth, Second Edition" for starters ;-). I should read it probably. Thanks for the clarification and for the help in asking the correct question :). +1 + accept – bas Feb 17 '13 at 09:16
  • @bas That is a contender for "because he is Jon Skeet". I guess my question was more .. how does he come across the material for the book and these sorts of answers. I can't seem to find this level of detail documented anywhere. I'm fascinated by this sort of information.. so its kinda frustrating for me having to wait for these questions to be asked and this level of answer to be given :P – Simon Whitehead Feb 17 '13 at 09:17
  • @SimonWhitehead: Reading the CLI spec in this case :) – Jon Skeet Feb 17 '13 at 09:24
  • @JonSkeet It is probably time I got stuck into the specs I think. Thanks! – Simon Whitehead Feb 17 '13 at 09:26
  • It's also funny that a so-called `String[*]`, i.e. a one-dimensional string array whose index is not zero-based, works with the non-generic `IList` interface. For example: `System.Collections.IList arr = Array.CreateInstance(typeof(string), new[] { 21, }, new[] { -10, }); arr[-7] = "works";` And a multi-dimensional (possibly zero-based) array does implement non-generic `IList`, bot using [the indexer (which has only one index parameter)](http://msdn.microsoft.com/en-us/library/system.collections.ilist.item.aspx) fails run-time, of course. – Jeppe Stig Nielsen Feb 17 '13 at 09:40
  • @JonSkeet I don't know how else to get in contact with you. Your third edition can be ordered in MEAP (no idea what it means). If I order it, will it be an ebook only as amazon states? Do I need to wait to get a hard-copy? If there is a more appropriate place for this question let me know and my sincere apologies for asking it here. – bas Feb 17 '13 at 12:14
  • @bas: MEAP=Manning Early Access Program. You can order either ebook or hard copy; if you buy the hard copy you'll get the ebook free. If you order the MEAP you won't get hard copy until the final book is ready, of course, but you get the "preview" version of the ebook immediately. For more details, email me (skeet@pobox.com) – Jon Skeet Feb 17 '13 at 12:30
1

EDIT: Originally thought the OP was asking about IList and not IList<T>.

...because arrays implement IList:

public abstract class Array : ICloneable, IList, ICollection, IEnumerable, IStructuralComparable, IStructuralEquatable
//                                        ^^^^^
Simon Whitehead
  • 63,300
  • 9
  • 114
  • 138
1

On a slightly related note:

It's quite unfortunate that T[] implements IList<T> sometimes. Consider the following code:

int[] array = new int[10];
IList<int> list = array; // Compiles
list.Add(1);             // Runtime error. Ew!

Not very nice really.

For this reason, you need to think carefully before using IList<T> instead of T[].

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
  • 1
    The underlying problem is that the collection interfaces are badly designed. Related: [Why array implements IList?](http://stackoverflow.com/questions/5968708/why-array-implements-ilist) – CodesInChaos Feb 17 '13 at 11:52