20

From msdn:

Represents a generic read-only collection of key/value pairs.

However consider following:

class Test
{
    public IReadOnlyDictionary<string, string> Dictionary { get; } = new Dictionary<string, string>
    {
        { "1", "111" },
        { "2", "222" },
        { "3", "333" },
    };

    public IReadOnlyList<string> List { get; } =
        (new List<string> { "1", "2", "3" }).AsReadOnly();
}

class Program
{
    static void Main(string[] args)
    {
        var test = new Test();

        var dictionary = (Dictionary<string, string>)test.Dictionary; // possible
        dictionary.Add("4", "444"); // possible
        dictionary.Remove("3"); // possible

        var list = (List<string>)test.List; // impossible
        list.Add("4"); // impossible
        list.RemoveAt(0); // impossible
    }
}

I can easily cast IReadOnlyDictionary to Dictionary (anyone can) and change it, while List has nice AsReadOnly method.

Question: how to properly use IReadOnlyDictionary to make public indeed read-only dictionary ?

Sinatr
  • 20,892
  • 15
  • 90
  • 319
  • I think creating an *Adapter* over the `Dictionary` can help to expose only the **read-only** behaviour. – adricadar Sep 14 '15 at 08:50
  • You're misunderstanding what an interface does. It just describes a contract. `IList` could inherit `IReadOnlyCollection`, for example, but that doesn't make the list implementing `List` read-only. Is your actual question _"How can I make a read-only dictionary"_? – CodeCaster Sep 14 '15 at 08:50
  • @CodeCaster, hmm, yes. But not *making* it myself, rather reuse existing in .net type properly. – Sinatr Sep 14 '15 at 08:52
  • @adricadar, I am using properties. – Sinatr Sep 14 '15 at 08:54
  • Those interfaces were poorly named. This one should have been called IReadableDictionary. Its contract defines readability but says nothing about whether it's writable or not, and its name should have done the same. – Keith Robertson Mar 08 '23 at 23:35

1 Answers1

21

.NET 4.5 introduced the ReadOnlyDictionary type that you could use. It has a constructor that accepts an existing dictionary.

When targeting lower framework versions, use the wrapper as explained in Is there a read-only generic dictionary available in .NET? and Does C# have a way of giving me an immutable Dictionary?.

Please note that when using the latter class, the collection initializer syntax won't work; that gets compiled to Add() calls.

Community
  • 1
  • 1
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
  • 1
    Didn't noticed `ReadOnlyDictionary` (it's well hidden), thanks. I can use normal `Dictionary` with collection initializer as a constructor parameter for `ReadOnlyDictionary`. – Sinatr Sep 14 '15 at 09:00
  • 2
    You could also use [`ImmutableDictionary<>`](https://msdn.microsoft.com/en-us/library/dn467181%28v=vs.111%29.aspx) if you're using the latest version of .Net. (That's a hardcore immutable class ;) – Matthew Watson Sep 14 '15 at 09:02
  • @MatthewWatson, good to know, thanks. I wonder what is a difference, but that would be another question, right? – Sinatr Sep 14 '15 at 09:06
  • 2
    @Sinatr `ImmutableDictionary<>` is not a wrapper class and it is truely immutable,. `ReadOnlyDictionary` is only a wrapper and it's important to note that if you change the contents of the wrapped dictionary, the contents of the read-only dictionary also change. It's read-only, not immutable! – Matthew Watson Sep 14 '15 at 09:16
  • @MatthewWatson, thanks for explanation. I am not going to change dictionary content after creating instance (writable dictionary instance is not stored and `ReadOnlyDictionary.Dictionary` property is `protected`), so *read-only* is all I need. The idea with `ToBuilder() / ToImmutable()` is nice (multithreading?), might use `ImmutableDictionary` some day. – Sinatr Sep 14 '15 at 09:42