Принцип подстановки Лисков требует, чтобы подтипы удовлетворяли контрактам супертипов. В моем понимании это будет означать, что ReadOnlyCollection<T>
нарушает Лисков. Контракт ICollection<T>
предоставляет операции Add
и Remove
, но подтип только для чтения не соответствует этому контракту. Например,
IList<object> collection = new List<object>();
collection = new System.Collections.ObjectModel.ReadOnlyCollection<object>(collection);
collection.Add(new object());
-- not supported exception
Очевидно, что необходимы неизменяемые коллекции. Что-то не так с тем, как .NET их моделирует? Как лучше это сделать? IEnumerable<T>
хорошо раскрывает коллекцию, по крайней мере, кажущуюся неизменной. Однако семантика сильно отличается, прежде всего потому, что IEnumerable
не раскрывает явно какое-либо состояние.
В моем конкретном случае я пытаюсь создать неизменяемый класс DAG для поддержки FSM. Мне, очевидно, понадобятся методы AddNode
/AddEdge
в начале, но я не хочу, чтобы можно было изменить конечный автомат, когда он уже запущен. Мне трудно представить сходство между неизменяемыми и изменяемыми представлениями DAG.
Прямо сейчас мой дизайн включает в себя предварительное использование DAG Builder, а затем создание неизменного графа один раз, после чего его больше нельзя редактировать. Единственный общий интерфейс между Builder и конкретной неизменной DAG — это Accept(IVisitor visitor)
. Я обеспокоен тем, что это может быть слишком сложным/слишком абстрактным перед лицом, возможно, более простых вариантов. В то же время у меня возникают проблемы с тем, что я могу выставлять методы в интерфейсе графа, которые могут выдать NotSupportedException
, если клиент получит конкретную реализацию. Как с этим справиться правильно?
IList<T>
включает тот факт, что список может быть только для чтения или нет из-за неявного свойстваICollection<T>.IsReadOnly
. Итак, что касается этого состояния «Только для чтения», я не думаю, что договор об интерфейсе/наследовании действительно что-то оговаривает сам по себе. Другими словами, если вы являетесьIList<T>
, вы можете свободно бросать вызов при вызове Add при условии, что IsReadOnly возвращает значение true. Я согласен, что на самом деле это не ответ на ваш вопрос :-) - person Simon Mourier   schedule 14.12.2012ReadOnlyCollection<T>
IList<T>
не так сильно нарушает LSP, как реализацияT[]
, посколькуReadOnlyCollection<T>
точно говорит, что запись не удастся. ХотяMammal[]
реализуетIList<Mammal>
, и индексированный установщик этогоIList<Mammal>
будет во время компиляции принимать что-либо типаMammal
, невозможно сказать, будет ли попытка сохранить конкретныйMammal
успешной, кроме как с использованием Reflection, или попытка перехвата исключение. - person supercat   schedule 09.02.2014