Is there a read-only generic dictionary available

2019-01-02 15:12发布

I'm returning a reference to a dictionary in my read only property. How do I prevent consumers from changing my data? If this were an IList I could simply return it AsReadOnly. Is there something similar I can do with a dictionary?

Private _mydictionary As Dictionary(Of String, String)
Public ReadOnly Property MyDictionary() As Dictionary(Of String, String)
    Get
        Return _mydictionary
    End Get
End Property

14条回答
栀子花@的思念
2楼-- · 2019-01-02 15:15

IsReadOnly on IDictionary<TKey,TValue> is inherited from ICollection<T> (IDictionary<TKey,TValue> extends ICollection<T> as ICollection<KeyValuePair<TKey,TValue>>). It is not used or implemented in any way ( and is in fact "hidden" through the use of explicitly implementing the associated ICollection<T> members ).

There are at least 3 ways I can see to solve the problem:

  1. Implement a custom read only IDictionary<TKey, TValue> and wrap / delegate to an inner dictionary as has been suggested
  2. Return an ICollection<KeyValuePair<TKey, TValue>> set as read only or an IEnumerable<KeyValuePair<TKey, TValue>> depending on the use of the value
  3. Clone the dictionary using the copy constructor .ctor(IDictionary<TKey, TValue>) and return a copy - that way the user is free to do with it as they please and it does not impact on the state of the object hosting the source dictionary. Note that if the dictionary you are cloning contains reference types ( not strings as shown in the example ) you will need to do the copying "manually" and clone the reference types as well.

As an aside; when exposing collections, aim to expose the smallest possible interface - in the example case it should be IDictionary as this allows you to vary the underlying implementation without breaking the public contract that the type exposes.

查看更多
弹指情弦暗扣
3楼-- · 2019-01-02 15:15

No, but it would be easy to roll your own. IDictionary does define an IsReadOnly property. Just wrap a Dictionary and throw a NotSupportedException from the appropriate methods.

查看更多
不流泪的眼
4楼-- · 2019-01-02 15:16

A read-only dictionary can to some extent be replaced by Func<TKey, TValue> - I usually use this in an API if I only want people performing lookups; it's simple, and in particular, it's simple to replace the backend should you ever wish to. It doesn't provide the list of keys, however; whether that matters depends on what you're doing.

查看更多
无色无味的生活
5楼-- · 2019-01-02 15:16

You could create a class that only implements a partial implementation of the dictionary, and hides all the add/remove/set functions.

Use a dictionary internally that the external class passes all requests to.

However, since your dictionary is likely holding reference types, there is no way you ca stop the user from setting values on the classes held by the dictionary (unless those classes themselves are read only)

查看更多
梦寄多情
6楼-- · 2019-01-02 15:16

Now, there are Microsoft Immutable Collections (System.Collections.Immutable). Get them via NuGet.

查看更多
唯独是你
7楼-- · 2019-01-02 15:18

It was announced in the recent BUILD conference that since .NET 4.5, the interface System.Collections.Generic.IReadOnlyDictionary<TKey,TValue> is included. The proof is here (Mono) and here (Microsoft) ;)

Not sure if ReadOnlyDictionary is included too, but at least with the interface it shouldn't be difficult to create now an implementation which exposes an official .NET generic interface :)

查看更多
登录 后发表回答