У меня есть методы, возвращающие личные коллекции вызывающему, и я хочу, чтобы вызывающий вызывал изменение возвращаемых коллекций.Как предотвратить изменение метода возвращаемой коллекции?
private readonly Foo[] foos;
public IEnumerable<Foo> GetFoos()
{
return this.foos;
}
На данный момент частная коллекция представляет собой фиксированный массив, но в будущей коллекции может стать списком, если возникнет необходимость в добавлении новых элементов во время выполнения.
Существует несколько решений, позволяющих избежать изменения коллекции. Возвращение IEnumerable<T>
- это самое простое решение, но вызывающий может по-прежнему отображать возвращаемое значение до IList<T>
и изменять коллекцию.
((IList<Foo>)GetFoos())[0] = otherFoo;
Клонирование коллекций имеет очевидный недостаток, что существуют две коллекции, которые могут развиваться независимо. До сих пор я рассматривал следующие варианты.
- Обнаруживание коллекции в
ReadOnlyCollection<T>
. - Возврат одного из итераторов LINQ, определяемых классом
Enumerable
, путем выполнения фиктивной проекции, такой какlist.Select(item => item)
. На самом деле я считаю использованиеWhere(item => true)
, потому что возвращенный итератор выглядит более легким. - Написание пользовательской оболочки.
Что мне не нравится об использовании ReadOnlyCollection<T>
является то, что он реализует IList<T>
и вызов Add()
или доступ к индексатор будет вызывать исключения. Хотя это абсолютно верно в теории, почти никаких реальных проверок кода IList<T>.IsReadOnly
или IList<T>.IsFixedSize
.
Использование итераторов LINQ - я завернул код в метод расширения MakeReadOnly()
- предотвращает этот сценарий, но у него есть вкус взлома.
Написание пользовательской обертки? Переосмыслить колесо?
Любые мысли, соображения или другие решения?
Хотя разметили этот вопрос, я обнаружил this Stack Overflow question я не замечал раньше. Jon Skeet предлагает использовать «LINQ hack» тоже, но еще эффективнее, используя Skip(0)
.
Если есть проблемы с безопасностью (потенциально враждебные абоненты), я вообще не беспокоюсь о защите от неразумного каста или вызова Add на ReadOnlyCollection. Глупые разработчики также могут использовать функции отражения и доступа. Трудно сделать код идиотом. Целью является защита от невинного использования публичного интерфейса. – TrueWill