A Generic Read-Only Dictionary
The .NET framework includes several types of collection that are designed for use in object models. Amongst these is the ReadOnlyCollection that allows the creation of collections that may not be modified. However, there is no read-only Dictionary type.
Object Model Collections
The .NET framework versions 2.0 and later include the System.Collections.ObjectModel namespace. This namespace contains various collection classes that are designed to be used when creating reusable object models, such as those held in a class library. These types should be the preferred choices when creating public methods and properties that return lists of values or objects.
One of the interesting classes in the System.Collections.ObjectModel namespace is the ReadOnlyCollection. This class provides a wrapper to an existing collection but without the members that permit you to add, remove or modify items. This is useful when returning a list of values to a calling method where you do not wish for the collection to be changed. NB: The collection may not be modified but if it contains reference types, the individual items may be.
To create an instance of the ReadOnlyCollection class, you must first create another, writeable collection. This is passed to the constructor of the ReadOnlyCollection object, as in the following sample code:
Collection<string> writeable = new Collection<string>();
ReadOnlyCollection<string> readOnly = new ReadOnlyCollection<string>(writeable);
Unfortunately, the .NET framework does not provide a read-only dictionary or hash table class. In this article we will implement such a dictionary as a generic, "ReadOnlyDictionary" class.
The ReadOnlyDictionary class will behave in a similar manner to the generic ReadOnlyCollection class. The key difference will be that the class will be a wrapper for a dictionary containing key / value pairs, rather than for a simple list of values. The class will meet the following requirements:
- The dictionary will contain key / value pairs where both the key and value are generic types, permitting any type of key and value to be held.
- It will not be possible to add, remove or replace items in the collection. Changes to the individual items in the collection will be permitted if their types permit. These changes will be reflected in the underlying dictionary also.
- The ReadOnlyDictionary class will implement the generic IDictionary interface so that it may be used wherever an IDictionary object is expected. In order to implement the IDictionary interface, the ReadOnlyDictionary will also implement the generic ICollection and IEnumerable interfaces and the non-generic IEnumerable interface.
Creating the ReadOnlyDictionary Project
The ReadOnlyDictionary class described in this article can be created in a class library project or in any other type of C# project, depending upon your requirements. The code that can be downloaded from the link at the top of the page uses a class library project, named "ReadOnlyDictionaryDemo".
Creating the ReadOnlyDictionary Class
To create the class definition, change the name of the default class in the project to "ReadOnlyDictionary" and modify the declaration for the class as follows:
public sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey,TValue>
In the above declaration, the class is defined as sealed to prevent it being subclassed with a type that would permit changes to the dictionary's contents. If you prefer to allow other classes to inherit from the new dictionary type, remove the sealed keyword.
The read-only dictionary uses two generic types. The first, named "TKey", defines the type of the key for each element in the collection. The second, "TValue", defines the type of each value. The actual types used for an instance of the ReadOnlyDictionary will be determined when the object is declared.
The final part of the declaration indicates that the new class will implement the generic IDictionary interface, using the same types for the keys and values. This will allow the ReadOnlyDictionary to be used wherever an IDictionary is expected, assuming that it will not require that the dictionary be modified.
The class will use functionality from several namespaces. To allow a simplified syntax, ensure that you include the following using directives at the top of the class's code file:
Declaring the Underlying Dictionary
The ReadOnlyDictionary class will provide a wrapper to any dictionary class that implements the generic IDictionary interface. To permit this, we need to create a private field to contain a reference to that dictionary. To do so, add the following declaration within the class's code block.
private IDictionary<TKey, TValue> _dictionary;
Creating the Constructor
As with the ReadOnlyCollection, the ReadOnlyDictionary class will include a single constructor. This constructor will accept a parameter containing the dictionary to be used as the source of the collection's items. As we do not know exactly which type of dictionary will be provided, this parameter will accept any object that implements IDictionary.
public ReadOnlyDictionary(IDictionary<TKey, TValue> source)
_dictionary = source;
NB: To keep the example code as simple as possible, no validation code is included. You should add validation as required. For example, you may wish to add a check to ensure that the source dictionary is not null.
28 February 2009