Я возвращаю ссылку на словарь в моем свойстве только для чтения. Как я могу запретить потребителям изменять мои данные? Если бы это было, IList
я мог бы просто вернуть его AsReadOnly
. Есть ли что-то подобное, что я могу сделать со словарем?
Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
Get
Return _mydictionary
End Get
End Property
.net
dictionary
readonly
Роб Соберс
источник
источник
Ответы:
Вот простая реализация, которая оборачивает словарь:
источник
.NET 4.5
.NET Framework 4.5 BCL представляет
ReadOnlyDictionary<TKey, TValue>
( источник ).Поскольку .NET Framework 4.5 BCL не включает
AsReadOnly
словари for, вам необходимо написать свой собственный (если вы этого хотите). Это будет что-то вроде следующего, простота которого, возможно, подчеркивает, почему это не было приоритетом для .NET 4.5..NET 4.0 и ниже
До .NET 4.5 не было никакого класса .NET Framework, который оборачивает
Dictionary<TKey, TValue>
как ReadOnlyCollection обертывание List . Тем не менее, это не сложно создать.Вот пример - есть много других, если вы Google для ReadOnlyDictionary .
источник
AsReadOnly()
метод по обычномуDictionary<,>
, поэтому мне интересно, сколько людей обнаружат свой новый тип. Однако этот поток переполнения стека поможет.На недавней конференции BUILD было объявлено, что начиная с .NET 4.5, интерфейс
System.Collections.Generic.IReadOnlyDictionary<TKey,TValue>
включен. Доказательство здесь (моно) и здесь (Microsoft);)Не уверен,
ReadOnlyDictionary
включен ли он тоже, но, по крайней мере, с интерфейсом теперь не составит труда создать реализацию, которая предоставляет официальный универсальный интерфейс .NET :)источник
ReadOnlyDictionary<TKey, TValue>
(.Net 4.5) - msdn.microsoft.com/en-us/library/gg712875.aspxНе стесняйтесь использовать мою простую обертку. Он НЕ реализует IDictionary, поэтому он не должен генерировать исключения во время выполнения для методов словаря, которые могли бы изменить словарь. Методы изменения просто отсутствуют. Я сделал свой собственный интерфейс для этого, названный IReadOnlyDictionary.
источник
IDictionary
договор. Я думаю, что с точки зрения ООПIDictionary
правильнее наследоватьIReadOnlyDictionary
.IDictionary
(для текущегоIReadOnlyDictionary
) иIMutableDictionary
(для текущегоIDictionary
).IsReadOnly on
IDictionary<TKey,TValue>
наследуется отICollection<T>
(IDictionary<TKey,TValue>
расширяетсяICollection<T>
какICollection<KeyValuePair<TKey,TValue>>
). Он не используется и не реализуется каким-либо образом (и фактически является «скрытым» за счет использования явной реализации связаннойICollection<T>
членов).Есть как минимум 3 способа решения проблемы:
IDictionary<TKey, TValue>
и перенос / делегирование во внутренний словарь, как было предложеноICollection<KeyValuePair<TKey, TValue>>
набора только для чтения или вIEnumerable<KeyValuePair<TKey, TValue>>
зависимости от использования значения.ctor(IDictionary<TKey, TValue>)
и верните копию - таким образом, пользователь может делать с ним все, что ему угодно, и это не влияет на состояние объекта, в котором находится исходный словарь. Обратите внимание, что если клонируемый словарь содержит ссылочные типы (а не строки, как показано в примере), вам нужно будет выполнить копирование «вручную» и клонировать ссылочные типы.Как в сторону; при представлении коллекций стремитесь предоставить наименьший возможный интерфейс - в данном случае это должен быть IDictionary, поскольку это позволяет варьировать базовую реализацию, не нарушая публичный контракт, который предоставляет тип.
источник
Доступный только для чтения словарь может быть в некоторой степени заменен на
Func<TKey, TValue>
- обычно я использую его в API, если мне нужны только люди, выполняющие поиск; это просто и, в частности, просто заменить бэкэнд, если вы когда-нибудь захотите. Однако он не предоставляет список ключей; имеет ли это значение, зависит от того, что вы делаете.источник
Нет, но это было бы легко сделать самостоятельно. IDictionary определяет свойство IsReadOnly. Просто оберните словарь и сгенерируйте NotSupportedException из соответствующих методов.
источник
Нет доступных в BCL. Однако я опубликовал ReadOnlyDictionary (названный ImmutableMap) в моем проекте BCL Extras.
Помимо того, что он является полностью неизменным словарем, он поддерживает создание прокси-объекта, который реализует IDictionary и может использоваться в любом месте, где берется IDictionary. Он будет выдавать исключение всякий раз, когда вызывается один из мутирующих API.
источник
Вы можете создать класс, который реализует только частичную реализацию словаря и скрывает все функции добавления / удаления / установки.
Используйте внутренний словарь, к которому внешний класс передает все запросы.
Однако, поскольку ваш словарь, скорее всего, содержит ссылочные типы, вы не сможете остановить пользователя от установки значений для классов, содержащихся в словаре (если только эти классы не предназначены только для чтения)
источник
Я не думаю, что есть простой способ сделать это ... если ваш словарь является частью пользовательского класса, вы можете достичь этого с помощью индексатора:
источник
+1 Отличная работа, Томас. Я сделал ReadOnlyDictionary еще на один шаг вперед.
Многое , как решение Дэйла, я хотел удалить
Add()
,Clear()
,Remove()
и т.д. от IntelliSense. Но я хотел, чтобы мои производные объекты реализовалиIDictionary<TKey, TValue>
.Кроме того, я хотел бы, чтобы следующий код сломался: (Опять же, решение Дейла делает это тоже)
Строка Add () приводит к:
Вызывающий все еще может использовать его
IDictionary<TKey, TValue>
, ноNotSupportedException
он будет поднят, если вы попытаетесь использовать не только для чтения участников (из решения Томаса).Во всяком случае, вот мое решение для тех, кто также хотел это:
источник
Теперь есть неизменные коллекции Microsoft (
System.Collections.Immutable
). Получить их через NuGet .источник
источник
public IEnumerable<KeyValuePair<string, string>> MyDictionary() { return _mydictionary; }
Это плохое решение, смотрите внизу.
Для тех, кто все еще использует .NET 4.0 или более раннюю версию, у меня есть класс, который работает так же, как и в принятом ответе, но он намного короче. Он расширяет существующий объект Dictionary, переопределяя (фактически скрывая) определенные члены, чтобы они вызывали исключение при вызове.
Если вызывающая сторона пытается вызвать Add, Remove или какую-либо другую мутирующую операцию, имеющуюся во встроенном словаре, компилятор выдаст ошибку. Я использую устаревшие атрибуты, чтобы вызвать эти ошибки компилятора. Таким образом, вы можете заменить Dictionary на этот ReadOnlyDictionary и сразу увидеть, где могут быть какие-либо проблемы, без необходимости запуска приложения и ожидания исключений во время выполнения.
Взглянуть:
У этого решения есть проблема, указанная @supercat, показанной здесь:
Вместо того, чтобы выдавать ошибку времени компиляции, как я ожидал, или исключение времени выполнения, как я надеялся, этот код выполняется без ошибок. Он печатает четыре номера. Это делает мой ReadOnlyDictionary ReadWriteDictionary.
источник
Dictionary<TKey,TValue>
без каких-либо жалоб компилятора, и приведение или приведение ссылки к типу простого словаря снимет любые защиты.Dictionary
сClone
методом, который прикован кMemberwiseClone
. К сожалению, хотя должна быть возможность эффективно клонировать словарь путем клонирования резервных хранилищ, тот факт, что резервные хранилища,private
а неprotected
означает, что у производного класса нет возможности клонировать их; ИспользованиеMemberwiseClone
без клонирования резервных хранилищ будет означать, что последующие модификации, сделанные в исходном словаре, будут ломать клон, а модификации, сделанные в клоне, будут ломать оригинал.