Список только для чтения или неизменяемый список в .NET 4.0

100

Насколько я могу судить, в .NET 4.0 по-прежнему отсутствуют списки, доступные только для чтения. Почему во фреймворке до сих пор отсутствует эта функциональность? Разве это не одна из самых распространенных функциональных возможностей предметно-ориентированного дизайна ?

Одним из немногих преимуществ Java перед C # является то , что он представлен в форме метода Collections.unmodifiablelist (list) , который, похоже, давно назрел в IList <T> или List <T>.

Использование IEnumerable<T>- самый простой ToListвариант решения вопроса - можно использовать и вернуть копию.

Крис С
источник
Похоже, что единственный реальный способ иметь истинный режим только List<T>для чтения - это написать свой собственный, я не знаю встроенного класса, который поддерживает все готовые функции «только для чтения» List<T>, такие как Containsзапросы LINQ и т. Д.
jrh

Ответы:

146

Вы ищете ReadOnlyCollection, который существует со времен .NET2.

IList<string> foo = ...;
// ...
ReadOnlyCollection<string> bar = new ReadOnlyCollection<string>(foo);

или

List<string> foo = ...;
// ...
ReadOnlyCollection<string> bar = foo.AsReadOnly();

Это создает доступное только для чтения представление , которое отражает изменения, внесенные в обернутую коллекцию.

Лука
источник
1
Я чувствую себя немного глупо, задав этот вопрос сейчас - и ничего не знаю о ReadOnlyCollection
Chris S
54
не будь - я тоже, когда я пошел искать то же самое и нашел Ваш вопрос
Роланд Тепп
9
Это досадно сложно найти. Он находится в пространстве имен System.Collections.ObjectModel вместо System.Collections.Generic, где я ожидал найти его. Полагаю, это потому, что это было до того, как существовало универсальное пространство имен. Тем не менее, я бы ожидал, что базовый класс останется в ObjectModel, а общий класс будет добавлен в Generic. Я полагаю, у них были свои причины, но меня это раздражает.
BlueMonkMN
5
@BlueMonkMN: обратитесь к этой статье, чтобы узнать, почему она отделена от пространства имен Collections.Generic.
Uchitha
7
Но это не список, это коллекция. Поэтому, если вы его используете, вам нужно изменить весь свой код, чтобы использовать Collection вместо List.
Роман Забицкий
13

Для тех, кто любит использовать интерфейсы: .NET 4.5 добавляет общий IReadOnlyListинтерфейс, который, List<T>например, реализован .

Он похож на свойство индексатора IReadOnlyCollectionи добавляет его Item.

Мартин
источник
11

Если наиболее распространенным шаблоном списка является перебор всех элементов IEnumerable<T>или он также IQueryable<T>может эффективно действовать как список только для чтения.

Ана Беттс
источник
4
Если вы предоставляете свой список как IEnumerable, то потребитель может просто вернуть его обратно в список и изменить его.
JulianR
4
Конечно, но это не должно быть пуленепробиваемой мерой - вы также, вероятно, могли бы прочитать личные поля и отследить исходный список. Это больше похоже на описание намерения, чтобы он оставался доступным только для чтения.
Ана Беттс,
5
Вы также не изменяете исходный список, звоня ToList(), только копию
Крис С.
Обратите внимание, что IEnumerableэто не полный набор методов «только для чтения», например, он не содержит таких методов, как Contains.
jrh
8

В 2.0 вы можете позвонить, AsReadOnlyчтобы получить версию списка только для чтения. Или оберните существующее IListв ReadOnlyCollection<T>объект.

Пол Александр
источник
это эквивалент Collections.unmodifiablelist (list), который я искал
Chris S,
Я пропустил это в .NET 4, потому что я использовал IList <T> вместо истинного List <T>. Обязательно обратите внимание на то, что AsReadOnly по-прежнему доступен в .NET 4, если вы имеете дело с List <T>.
BlueMonkMN