Making a collection immutable

A friend recently asked for suggestions about creating a class that is mutable up to a point (while it’s being constructed), and then immutable once clients begin to use it. His solution was to add a flag that could be set to make the thing read-only. For example, the class below is mutable up to the point when the _inUse field is set.

    public static class LabelsArray
    {
        private static Dictionary<int, string> _items = new Dictionary<int,string>();
        private static bool _inUse = false;

        public static void SetInUse()
        {
            _inUse = true;
        }

        public static void LoadFromFile(string f)
        {
            if (_inUse)
                throw new ApplicationException("no modifications allowed.");
            // load labels from a file
        }

        public static void AddLabel(int key, string val)
        {
            if (_inUse)
                throw new ApplicationException("no modifications allowed.");
            // add a label
        }

        public static string this[int key]
        {
            get { return _items[key]; }
        }

        public static bool TryGetValue(int key, out string val)
        {
            return _items.TryGetValue(key, out val);
        }
    }

Code that uses this class would initialize it by calling LoadFromFile and AddKeyValue as appropriate and, before creating any objects that use the labels, would call SetInUse to prevent it from being modified. Something like this:

    LabelsArray.LoadFromFile("foo");
    LabelsArray.AddKeyValue("joe", "programmer");
    LabelsArray.SetInUse();
    // The object can no longer be modified

His application was somewhat more complex than that, but that’s essentially what he described.

In a program that only needs one LabelsArray, this model works well. It’s quick to implement and does the job. It’s not a pattern you’d want to use if you have multiple labels arrays, though, unless you want to duplicate all that code for every different array. Also, that _inUse flag is kind of messy. Wouldn’t it be nice if you could implement this without having to resort to a flag?

How about writing code that constructs a dictionary and then wraps it in a read-only container? Something like this:

    public ReadOnlyDictionary<int, string> CreateLabelsArray()
    {
        var dict = new Dictionary<int, string>();
        // code here loads data from file,
        // adds other key/value pairs, etc.
        // And, finally:
        return new ReadOnlyDictionary<int, string>(dict);
    }

Clients make a single call to create the dictionary and get a read-only reference to it:

    var myLabels = CreateLabelsArray();

ReadOnlyDictionary creates a read-only wrapper around the dictionary that you pass to the constructor. Because the CreateLabelsArray method created the original dictionary and only the ReadOnlyDictionary instance maintains a reference to it, there is no way that the dictionary can be modified.

I like this solution because it eliminates the flag, and I can easily create multiple labels arrays. If I really need a that labels array to be static, I can declare a static reference and avoid the static class. In my experience, you should be careful with static classes.

If the collection you’re working with isn’t a dictionary, you might need a ReadOnlyCollection (essentially an immutable List<T>) rather than a ReadOnlyDictionary.

Those two collections are very useful in ensuring that critical data is not inadvertently modified. You’ll be surprised by how many problems you can solve by using these two collection types with a technique similar to what I showed above. If ReadOnlyDictionary and ReadOnlyCollection don’t quite fit your requirement, it’s pretty easy to create your own class that works in much the same way.

In the example I showed above, the dictionary returned by CreateLabelsArray is guaranteed to be thread-safe because there is no possible way that the underlying dictionary can be modified. Clients can query it with impunity. If instead you were to write code that maintains a reference to the underlying mutable dictionary, then you have a potential problem. Clients that reference the ReadOnlyDictionary can’t modify it, but they might fail if some other part of the code that has a reference to the underlying dictionary modifies the dictionary concurrently with clients’ queries.

If you’re going to use ReadOnlyDictionary or ReadOnlyCollection, especially in multithreaded code, I strongly recommend that you use the model I showed above: create the underlying collection, instantiate the read-only version, and then discard your reference to the mutable collection. If you maintain a reference to the mutable collection, you could inadvertently modify it and create a problem that is often difficult to track down.

Comments are closed.

Categories

A sample text widget

Etiam pulvinar consectetur dolor sed malesuada. Ut convallis euismod dolor nec pretium. Nunc ut tristique massa.

Nam sodales mi vitae dolor ullamcorper et vulputate enim accumsan. Morbi orci magna, tincidunt vitae molestie nec, molestie at mi. Nulla nulla lorem, suscipit in posuere in, interdum non magna.