Подтвердить что ты не робот

С#: транзитивное наследование

Наследуется транзитивное отношение в С#?

Я спрашиваю, потому что я не могу понять, почему IList<T> реализует ICollection<T> и IEnumerable<T>, поскольку ICollection<T> уже реализует IEnumerable<T>

Спасибо за разъяснение этого для меня.

4b9b3361

Ответ 1

AFAIK, на самом деле неважно, объявили ли вы IList<T> как:

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

или просто как:

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

Любой класс, который хочет реализовать IList<T>, должен будет реализовать все эти интерфейсы, т.е. также унаследованные.

Очевидно, что если вы внедрили этот интерфейс без реализации методов GetEnumerator интерфейсов IEnumerable/IEnumerable<T>, вы получите ошибку компилятора; этого "доказательства" демонстрацией должно быть достаточно, чтобы сказать вам, что "наследование интерфейса" действительно транзитивно.


Sidenote 1. На боковой ноте (и слегка не по теме) подумайте, что вы также можете сделать следующее:

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

interface IFoo
{
    void Foo();
}

class Derived : Base, IFoo 
{ }

Derived фактически не реализует IFoo; его базовый класс Base предоставляет метод Foo, но явно не реализует сам IFoo.

Это хорошо компилируется, похоже, потому что все методы, требуемые интерфейсами, есть. (Я оставлю это и оставлю сейчас техническую беседу.)

Причина, по которой я упоминаю это, казалось бы, несвязанное явление, заключается в том, что мне нравится думать о наследовании интерфейса таким образом: вам нужно реализовать все методы, требуемые интерфейсами, указанными в объявлении класса. Поэтому, когда я вижу

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

вместо того, чтобы сказать: "ICollection<T> наследует IEnumerable<T>", я мог сказать себе: "ICollection<T> требует от всех реализующих классов, которые они реализуют IEnumerable<T>, также."


Sidenote 2. Чтобы завершить этот ответ еще одним эпизодом, связанным с анекдотом (я обещаю, что это будет последний):

Некоторое время назад я смотрел видео Inside.NET Rx и IObservable/IObserver в BCL на канале 9. Поскольку вы теперь эти два новых интерфейса, выходящие из Rx, были введены в BCL с .NET 4. Одна особенность заключается в том, что когда вы подписываетесь на наблюдатель до наблюдаемого через observable.Subscribe(observer), все, что вы вернете, - это анонимный IDisposable. Почему?

Как говорят говорящие в этом видео, они могли бы дать IDisposable более описательное имя (например, ISubscription) через имя типа "псевдоним", определяемое следующим образом:

interface ISubscription : IDisposable {}
Тем не менее, они, наконец, решили против этого. Они полагали, что после возврата ISubscription из метода Subscribe уже не будет очевидно, что возвращаемое значение должно быть Dipose d.

Так что еще одна слегка проблематичная сторона "наследования интерфейсов", о которой следует помнить.

Ответ 2

Это транзитивно во всех отношениях. Вероятно, инструмент, который вы используете для поиска иерархии наследования, имеет определенный способ его отображения. Невозможно реализовать интерфейс, хотя вы можете реализовать его явно и тем самым скрыть его от intellisense.

Как автор IList, вы можете свободно выбирать из ICollection только или из ICollection и IEnumerable. IEnumerable будет избыточным в этом случае и помечен resharper.