26

For a very long time I was curious about the following:

int[] array = new int[1];
int iArrayLength = array.Length;    //1

Since arrays implement the IList interface, the following is allowed:

int iArrayCount = ((IList<int>)array).Count;    //still 1

BUT:

int iArrayCount = array.Count;  //Compile error. WHY?
int iArrayLength = array.Length;    //This is what we learned at school!

The question: How can an array implement IList<T> (especially the int Count { get; } property from IList<T>) without allowing it to be used on the base class?

newfurniturey
  • 37,556
  • 9
  • 94
  • 102
Gerrit
  • 532
  • 4
  • 10
  • You could probably simulate this yourself by shadowing the 'Count' property from the base class in your own inherited class, and make it private instead. VB.NET has an explicit keyword 'Shadows' for this, not sure about C#, thoug. – Joachim VR Sep 17 '12 at 14:28
  • You're title is mistakable. Arrays actually implement `Count` from [`ICollection`](http://msdn.microsoft.com/en-us/library/system.collections.icollection.count.aspx): `int ICollection.Count { get { return this.Length; } }` – Tim Schmelter Sep 17 '12 at 14:29
  • @TimSchmelter but `IList` inherits from `ICollection`; `ICollection` also has a `Count` property, so all types implementing `IList` must also implement `ICollection.Count`. True, the property is not defined in `IList`, but the question is a reasonable one. – phoog Sep 17 '12 at 14:36
  • @phoog: Apart of the fact that it's not a property of `IList`, it **is** implemented in Array, that was the main reason why i said that the title is mistakable (_"..without implementing.."_). – Tim Schmelter Sep 17 '12 at 14:44
  • 1
    @TimSchmelter aha, I see, I misunderstood your point. But if you read the title from the perspective of not knowing about explicit interface implementation, the question makes perfect sense. ("Mistaken", by the way, not "mistakable"). – phoog Sep 17 '12 at 15:00

2 Answers2

32

This is known as an explicit interface member implementation. The interface member is not exposed as a public member of the type, but it is available by casting the reference to the interface type.

This can be done in C# like this:

interface I
{
    void M();
}

class C : I
{
    public int P { get; set; }
    void I.M() { Console.WriteLine("M!"); }
}

Then you can use these types like this:

C obj = new C();
obj.P = 3;
((I)obj).M();

But this won't compile:

obj.M();

As JeffN825 notes, one reason for implementing the interface members explicity is that they're not supported by the type. For example, Add throws an exception (relevant discussion). Another reason for implementing a member explicity is that it duplicates another public member with a different name. That's the reason Count is implemented explicitly; the corresponding public member is Length. Finally, some members are implemented implicitly, namely, the indexer. Both of these lines work (assuming arr is an array of int):

arr[0] = 8;
((IList<int>)arr)[0] = 8;
Community
  • 1
  • 1
phoog
  • 42,068
  • 6
  • 79
  • 117
  • "explicit interface member definition" a good keyword for google! I didn't know about it, thanks! It's interesting that is doesn't have any access modifier. So you can use your internal interfaces on public classes without having to implement all methods/properties as public, nice! – Gerrit Sep 17 '12 at 14:35
  • @Gerrit; actually, that's incorrect. It should be "explicit interface member implementation." I have corrected. – phoog Sep 17 '12 at 14:37
  • @Gerrit Eric Lippert has an interesting discussion about using internal interfaces on public types here: http://blogs.msdn.com/b/ericlippert/archive/2011/12/08/so-many-interfaces-part-two.aspx – phoog Sep 17 '12 at 14:40
  • 1
    @Gerrit Jon Skeet's extremely thorough answer here gives much more detail than mine: http://stackoverflow.com/a/11163336/385844 – phoog Sep 17 '12 at 14:55
  • @phoog Interesting link. Fascinating reading the Jon vs Hans debate :) – Simon Whitehead Jan 25 '13 at 03:36
13

Because an Array doesn't support all of the features of an IList (Add/Remove/etc), IList.Count (and several other methods) are all implemented privately (explicitly). You can see this in disassembly:

int ICollection.Count

If you really wanted to use Count, you could do

((IList)myArray).Count
Jeff
  • 35,755
  • 15
  • 108
  • 220