Почему List <T> реализует IReadOnlyList <T> в .NET 4.5?

Почему List<T> реализует IReadOnlyList<T> в .NET 4.5?

List<T> не читается только...

Ответ 1

Потому что List<T> реализует все необходимые методы/свойства/etc. (а затем некоторые) из IReadOnlyList<T>. Интерфейс - это контракт, в котором говорится: "Я могу сделать хотя бы эти вещи".

В документации для IReadOnlyList<T> говорится, что она представляет собой коллекцию элементов только для чтения.

Это правильно. В этом интерфейсе нет методов мутаторов. Это то, что доступно только для чтения, не так ли? IReadOnlyList<T> используется в "типичном" (контрактном) способе, а не как marker.

Ответ 2

Интерфейсы описывают только функциональные возможности, которые будут реализованы. Он не описывает функциональность, которая не будет реализована. IReadOnlyList - это неправильное имя интерфейса, поскольку он не может указывать, что функция записи не будет записана.

Методы/функции описывают, что вы можете прочитать содержимое списка. Интерфейс должен быть IReadableList вместо IReadOnlyList.

Ответ 3

Тот факт, что он реализует интерфейс, не означает, что он доступен только для чтения. Но поскольку он реализует интерфейс, вы можете передать его методам, ожидающим IReadOnlyList<T>. Таким образом, чтобы посмотреть на это, он реализует интерфейс списка только для чтения... наряду с некоторыми методами записи.

Ответ 4

Реализация интерфейса - это не то же самое, что "маркировка". List<T> также реализует IEnumerable<T>, но это не означает, что вы ограничены просто перечислением его.

Они добавили интерфейсы только для чтения для создания API, не так, чтобы вы могли пометить ваши типы только для чтения интерфейсом. Это позволяет мне использовать аргументы IReadOnlyCollection<T> для аргументов, когда я просто хочу знать количество элементов в коллекции, не перечисляя его, или IReadOnlyList<T>, когда мне нужно ссылаться на элементы в коллекции по их индексу. Это хорошо для всех - я могу быть конкретным о том, что мне нужно от моего вызывающего абонента, позволяя моему абоненту использовать любой тип коллекции, который он хочет, до тех пор, пока он соответствует минимальному стандарту, установленному через тип аргумента.

Итак, я думаю, что более сложный вопрос: почему бы вам не List<T> реализовать IReadOnlyList<T>?

Ответ 5

IReadOnlyList является заменой концепции "эталонной неизменности", найденной в С++, но не в С#. C++ эквивалент:

void func (T const * t) {...}

или точно эквивалентны, так как некоторые предпочитают:

void func (const T * t) {...}

В нем говорится, что функция func не мутирует объект (ы), который ссылается на его аргумент t, называемый "референтом" t. В нем ничего не говорится о том, что какой-либо другой код мутирует референт t или даже может.

Таким образом, интерфейс С# заменяет конструкцию компилятора. Почему С# не имеет понятия эталонной неизменности - это исторический вопрос: я думаю, что это была ошибка, но сейчас уже поздно исправить это. Я думаю, что обеспечение замены интерфейса является хорошим. Я использовал интерфейс точно так же, как IReadOnlyList < > в течение многих лет, к счастью, с другим именем IConstList < > . Я могу заменить мое использование IConstList < > с помощью IReadOnlyList < > .

Ответ 6

Интерфейсы IReadOnlyList и IReadOnlyCollection несколько сбивают с толку, потому что они не означают, что коллекция доступна только для чтения, только этот доступ доступен только для чтения. Из документация MSDN (прокрутите вниз до значков)

Содержимое элементов списка не гарантируется только для чтения.

Лучшее имя будет IReadable, см. Почему не общий ICollection реализует IReadOnlyCollection в .NET 4.5?. Кроме того, это означает, что IList должен наследовать IReadOnlyList, хотя это не связано с обратной совместимостью, см. Почему не IList<T> наследует от IReadOnlyList<T>?,

Ответ 7

Не правда ли, что код, запускающий IReadOnlyList (Of T), вызывает объект, который реализует этот интерфейс, обычно работает с тем же потоком выполнения. Это предотвращает изменение объекта самостоятельно, если только он не работает в другом потоке выполнения, но для этой ситуации у нас есть вызовы синхронизации для решения этой проблемы.