11

Is Inheritance a transitive relation in C#?

I am asking because I cannot understand why IList<T> implements ICollection<T> and IEnumerable<T> as ICollection<T> already implements IEnumerable<T>

Thanks for clarifying this for me.

LukeH
  • 263,068
  • 57
  • 365
  • 409
user388377
  • 185
  • 9
  • you can find some answers in this similar [question][1] [1]: http://stackoverflow.com/questions/1164757/why-arraylist-implement-ilist-icollection-ienumerable – DesignFirst Jan 30 '11 at 23:22
  • http://stackoverflow.com/questions/4754923/a-question-about-interface-inheritance-in-net/4755044#4755044 – explorer Jan 31 '11 at 04:35
  • This is also a duplicate of http://stackoverflow.com/questions/4817369/why-does-does-realy-list-implements-all-of-that-interfaces-not-just-ilistt/4818566#4818566 – Eric Lippert Jan 31 '11 at 06:49

2 Answers2

8

It is transitive in all regards. Probably the tool that you use to look at the inheritance hierarchy has a certain way of displaying it. There is no way to unimplement an interface although you can implement it explicitly and thereby hide it from intellisense.

As the author of IList you can freely choose to derive from ICollection only or from ICollection and IEnumerable. IEnumerable would be redundant in this case and flagged by resharper.

usr
  • 168,620
  • 35
  • 240
  • 369
  • Sorry for interrupting, but "and flagged by resharper" caught my attention. Resharper is only a tool, not a programming guru. It also flags many other things that if changed cause trouble later on. (eg. flags explicit declarations to be changed to implicit (var)) – kubal5003 Jan 30 '11 at 23:46
  • Yes. I only meant that sentence to give social proof that the folks programming resharper agree with me. – usr Feb 04 '11 at 17:23
5

AFAIK, it doesn't truly matter whether you declared IList<T> as:

public interface IList<T> : ICollection<T>, IEnumerable<T> { ... }

or simply as:

public interface IList<T> : ICollection<T> { ... }

Any class that wants to implement IList<T> will have to implement all of these interfaces, i.e. also the inherited ones.

Obviously, if you implemented this interface without implementing the GetEnumerator methods of the IEnumerable/IEnumerable<T> interfaces, you'd get a compiler error; this "proof" by demonstration should be enough to tell you that "interface inheritance" is transitive, indeed.


Sidenote 1. On a side note (and slightly off-topic), consider that you can also do the following:

class Base
{
    public void Foo() { ... }
}

interface IFoo
{
    void Foo();
}

class Derived : Base, IFoo 
{ }

Derived doesn't actually implement IFoo; its base class Base provides method Foo, but doesn't explicitly implement IFoo itself.

This compiles well, seemingly because all the methods that are required by the interfaces are there. (I'll leave it at that and leave the exact technical talk aside for now.)

The reason why I'm mentioning this seemingly unrelated phenomenon is that I like to think of interface inheritance in this way: You need to implement all methods required by the interfaces specified in the class declaration. So when I see

interface ICollection<T> : IEnumerable<T> { ... }

instead of saying, "ICollection<T> inherits IEnumerable<T>", I could say to myself, "ICollection<T> requires of all implementing classes that they implement IEnumerable<T>, also."


Sidenote 2. To conclude this answer with yet another somewhat related anecdote (I promise it'll be the last one):

Some time ago I watched the video Inside .NET Rx and IObservable/IObserver in the BCL on Channel 9. As you might now, those two new interfaces, coming from Rx, were introduced into the BCL with .NET 4. One peculiar thing is that when you subscribe an observer to an observable via observable.Subscribe(observer), all you get back is some anonymous IDisposable. Why?

As the talkers explain in that video, they could have given the IDisposable a more descriptive name (such as ISubscription), via a type name "alias" defined as follows:

interface ISubscription : IDisposable {}

However, they finally decided against this. They figured that once an ISubscription is returned from the Subscribe method, it would no longer be obvious that the returned value needs to be Diposed.

So that's another slightly problematic side of "interface inheritance" that one should keep in mind.

stakx - no longer contributing
  • 83,039
  • 20
  • 168
  • 268