Почему List<T>
реализует IReadOnlyList<T>
в .NET 4.5?
List<T>
не только для чтения...
Почему List<T>
реализует IReadOnlyList<T>
в .NET 4.5?
List<T>
не только для чтения...
Поскольку List<T>
реализует все необходимые методы/свойства/и т.д. (а затем некоторые) из IReadOnlyList<T>
. Интерфейс — это контракт, в котором говорится: «Я могу делать как минимум эти вещи».
В документации для
IReadOnlyList<T>
говорится, что он представляет собой набор элементов только для чтения.
Вот так. В этом интерфейсе нет методов-мутаторов. Вот что значит только для чтения, верно? IReadOnlyList<T>
используется "типичным" (контрактным) способом, а не как маркер.
IsReadOnly
свойства IList
, которое равно false
, когда возможны чтение и запись. Интерфейс должен называться примерно так: IIndexable
.
- person nmclean; 04.02.2014
IImmutableList<T>
, который был бы реализован только неизменяемыми коллекциями [не обязательно коллекциями, поддерживаемыми массивом; возврат из IEnumerable<int>.Range
может реализовать IImmutableList<int>
, заставив индексатор вычислять по запросу значение n-го элемента.
- person supercat; 19.06.2014
Интерфейсы только описывают функциональность, которая будет реализована. Он не описывает функциональность, которая не будет реализована. Таким образом, IReadOnlyList является неправильным именем интерфейса, поскольку оно не может предписывать, что функция записи не будет записана.
Методы/функции описывают, что вы можете прочитать содержимое списка. Интерфейс должен был быть IReadableList вместо IReadOnlyList.
Реализация интерфейса — это не то же самое, что его «маркировка». List<T>
также реализует IEnumerable<T>
, но это не означает, что вы ограничены простым его перечислением.
Они добавили интерфейсы только для чтения для создания API, а не для того, чтобы вы могли пометить свои типы только для чтения интерфейсом. Это позволяет мне использовать IReadOnlyCollection<T>
для аргументов, когда я просто хочу узнать количество элементов в коллекции, не перечисляя их, или IReadOnlyList<T>
, когда мне нужно сослаться на элементы в коллекции по их индексу. Это хорошо для всех — я могу точно указать, что мне нужно от вызывающего объекта, и в то же время разрешить ему использовать любой тип коллекции, который он хочет, при условии, что он соответствует минимальному стандарту, который я установил для типа аргумента.
Поэтому я думаю, что более сложный вопрос заключается в том, почему нельзя вам List<T>
реализовать IReadOnlyList<T>
?
Тот факт, что он реализует интерфейс, не означает, что он доступен только для чтения. Но поскольку он реализует интерфейс, теперь вы можете передать его методам, которые ожидают IReadOnlyList<T>
. Таким образом, способ взглянуть на это заключается в том, что он реализует интерфейс списка только для чтения... вместе с некоторыми методами записи.
Интерфейсы IReadOnlyList
и IReadOnlyCollection
несколько сбивают с толку, потому что они не означают, что коллекция доступна только для чтения, просто поддерживается доступ только для чтения. Из документации MSDN (прокрутите вниз до раздела "Примечания").
Не гарантируется, что содержимое элементов списка будет доступно только для чтения.
Лучшее имя было бы IReadable
, см. Почему универсальное ICollection
не реализует IReadOnlyCollection
в .NET 4.5?. Кроме того, это означает, что IList
должен наследовать IReadOnlyList
, хотя это не связано с обратной совместимостью, см. Почему IList<T>
не наследуется от IReadOnlyList<T>
? .
IReadOnlyList заменяет концепцию «ссылочной неизменности», которая присутствует в C++, но не в C#. Эквивалент С++:
void func(T const* t) {...}
или точно эквивалентно, как некоторые предпочитают:
void func(const T* t) {...}
В нем говорится, что функция func не изменяет объект (объекты), на которые ссылается ее аргумент t, называемый «референтом» t. Он ничего не говорит о том, изменяет ли референт t какой-либо другой код и даже может ли.
Таким образом, интерфейс C# является заменой конструкции компилятора. Почему в C# нет концепции неизменяемости ссылок — исторический вопрос: я думаю, что это была ошибка, но сейчас уже слишком поздно ее исправлять. Я думаю, что предоставление замены интерфейса — это хорошо. Я годами использую точно такой же интерфейс, как IReadOnlyList‹>, но, к счастью, с другим именем IConstList‹>. Я могу заменить использование IConstList‹> на IReadOnlyList‹>.
Разве не правда, что код, выполняющий вызовы IReadOnlyList(Of T) к объекту, который реализует этот интерфейс, обычно выполняет один и тот же поток выполнения. Это предотвращает изменение объекта само по себе, если только он не работает в другом потоке выполнения, но для этой ситуации у нас есть вызовы синхронизации, чтобы решить эту проблему.