Re[2]: Всё-равно не понятно зачем ReadOnlyDictionary
От: SergeyT. США http://sergeyteplyakov.blogspot.com/
Дата: 18.06.13 21:34
Оценка: 55 (4) +1
Здравствуйте, igor-booch, Вы писали:

Смысл существования конкретных неизменяемых коллекций

Если речь идет о внутреннем коде, то вполне достаточно вместо List<T>/Dictionary<,> возвращать их "неизменяемый" интерфейс — IReadOnlyCollection<T>/IReadonlyList<T> или IReadOnlyDictionary<,>, соответственно.
В случае же библиотек, разработчики BCL, вероятно, посчитали такое разделение слишком слабым, поэтому решили ввести возможность завернуть любую список в оболочку с операциями только для чтения.

В подтверждение этой мысли можно привести рекомендацию из Framework Design Guidelines:

DO use ReadonlyCollection<T>, a subclass of ReadOnlyCollection<T>, or in rare cases IEnumerable<T> for properties or return values representing read-only collections.

In general, prefer ReadOnlyCollection<T>. ... In cases where you are sure that the only scenario you will ever want to support is forward-only iteration, you can simply use IEnumerable<T>.


На самом деле, тут есть пара моментов. Как тут уже проскакивало выше, даже неизменяемая коллекция не дает полной гарантии неизменяемости, поскольку всегда можно добраться до "нижележащей" коллекции с помощью рефлексии и изменить ее. С другой стороны, это явный хак, которым будут пользоваться на порядок реже, нежели "динамической" типизацией и привидением типа коллекции от IEnumerable<T> вверх к IList<T>.

Но, опять таки, нужно понимать, что подобная защита (как и приведенный выше совет) на порядок более актуален для библитек и не столь актуален для внутреннего кода. Поэтому в собственном (не библиотечном коде) я обычно возвращаю IEnumerable<T> или соответствующий read-only интерфейс не создавая лишнюю прослойку в виде неизменяемой коллекции.

IB> Так же высказывалась версия, что ReadOnlyDictionary нужен в ситуации когда вызываемый метод хочет IDictionary&lt;TKey, TValue&gt;, но вызывающий код не хочет давать методу менять словарь
Автор: AndrewVK
Дата: 12.06.13
. В пользу этой версии говорит тот факт, что и Dictionary и ReadOnlyDictionary реализуют одни и те же интерфейсы:


Это какой-то весьма частный случай, оправданный лишь тогда, когда мы точно знаем, что вызывающий код не меняет переданный словарь и мы этот самый код не можем изменить. Поскольку если это наш код, то нам стоит либо его изменить на использование read-only интерфейса, либо не париться по этому поводу. Передавать же read-only словарь в этот метод в надежде защититься от изменений не лучшая идея, поскольку в этом случае нужно хватать NotSupportedException, что на самом деле является сокрытием багов (что не входит в обязанности обработки исключений).

Почему IDictionary не наследует от IReadOnlyDictionary?

Здесь есть чисто техническое ограничение.
В языке C# не существует возможности переопределить (override) getter свойства, добавив при этом setter. Свойство Item интерфейса IReadOnlyDiction<,> содержит лишь get, и мы не можем нормальным образом добавить наследнику этого интерфейса (т.е. интерфейсу IDictionary<,>) еще и set. Вот простой пример:

interface IBase
{
    int Prop {get;}
}

interface IDerived : IBase
{
    int Prop {get; set;}
}

class D : IDerived
{
    public int Prop {get; set;}
}

class D2 : D, IBase
{
    int IBase.Prop {get {return 42;}}
}

void Main()
{
    D d = new D2(){Prop = 1};
    d.Prop = 1;
    d.Prop.Dump(); // 1
    IBase b = d;
    b.Prop.Dump(); // 42
}


Вместо заключения

В целом, косяков в коллекциях хватает. Сейчас уже никто не скажет, что такое коллекция, поскольку ICollection<T> содержит метод Add, а ICollection — нет; ведь поэтому Collection Initializer использует утиную типизацию.
Также сложно ответить, почему ICollection<T> содержит свойство IsReadOnly, а ICollection — нет. Почему Collection<T> реализует IList<T>, а IReadonlyCollection<T> реализует IReadOnlyList; и почему коллекций использует явную реализацию интерфейсов с бросанием исключения в "неподходящих" методах.

Скорее исторически так сложилось И как правильно написал AndrewVK разработчики BCL слишком поздно поняли важность строготипизированных read-only коллекций, что и привело к дополнительным косякам в дизайне.

З.Ы. В процессе подготовки ответа вырисовалась диаграмма классов для коллекций (не всех, но все же):

Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.