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.
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.
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 Dipose
d.
So that's another slightly problematic side of "interface inheritance" that one should keep in mind.
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