Question

I have a class in C# that contains a Dictionary, which I want to create and ensure nothing as added, edited or removed from this dictionary as long as the class which contains it exists.

readonly doesn't really help, once I tested and saw that I can add items after. Just for instance, I created an example:

public class DictContainer
{
    private readonly Dictionary<int, int> myDictionary;

    public DictContainer()
    {
        myDictionary = GetDictionary();
    }

    private Dictionary<int, int> GetDictionary()
    {
        Dictionary<int, int> myDictionary = new Dictionary<int, int>();

        myDictionary.Add(1, 2);
        myDictionary.Add(2, 4);
        myDictionary.Add(3, 6);

        return myDictionary;
    }

    public void Add(int key, int value)
    {
        myDictionary.Add(key, value);
    }

}

I want the Add method not to work. If possible, I want it not to even compile. Any suggestions?

Actually, I'm worried for it is code that will be open for a lot of people to change. So, even if I hide the Add method, it will be possible for someone to "innocently" create a method which add a key, or remove another. I want people to look and know they shouldn't change the dictionary in any ways. Just like I have with a const variable.

Was it helpful?

Solution

There's nothing in the .NET Framework to help you out here, but this post gives a pretty good implementation of a generic ReadOnlyDictionary in C#. It implements all the interfaces you might expect it to (IDictionary, ICollection, IEnumerable, etc.) and as a bonus, the entire class and its members are fully commented with XML.

(I've refrained from posting the code here, because it's really quite long with all the XML comments.)

OTHER TIPS

Hide the Dictionary totally. Just provide a get method on the DictContainer class that retrieves items from the dictionary.

public class DictContainer
{
    private readonly Dictionary<int, int> myDictionary;

    public DictContainer()
    {
        myDictionary = GetDictionary();
    }

    private Dictionary<int, int> GetDictionary()
    {
        Dictionary<int, int> myDictionary = new Dictionary<int, int>();

        myDictionary.Add(1, 2);
        myDictionary.Add(2, 4);
        myDictionary.Add(3, 6);

        return myDictionary;
    }

    public this[int key]
    {
        return myDictionary[key];
    }
}

Eh... then don't define the Add Method...

Keep the myDictionary variable private and expose a Getter/Indexer so that it can only be read from outside that class..

wonders if he's completely missing the point

There's no built-in way to do that, consider using a wrapper class.

interface IReadOnlyDic<Key, Value>
{
    void Add(Key key, Value value);
}
class ReadOnlyDic<Key, Value> : Dictionary<Key, Value>, IReadOnlyDic<Key, Value>
{
    public new void Add(Key key, Value value)
    {
        //throw an exception or do nothing
    }
    #region IReadOnlyDic<Key,Value> Members

    void IReadOnlyDic<Key, Value>.Add(Key key, Value value)
    {
        base.Add(key, value);
    }

    #endregion
}

to add custom items;

    IReadOnlyDic<int, int> dict = myDictInstance as IReadOnlyDic<int, int>;
    if (dict != null)
        dict.Add(1, 155);

and this is another way

class ReadOnlyDic<Key, Value> : Dictionary<Key, Value>
{
    private bool _locked = false;

    public new void Add(Key key, Value value)
    {
        if (!_locked)
        {
            base.Add(key, value);
        }
        else
        {
            throw new ReadOnlyException();
        }
    }
    public void Lock()
    {
        _locked = true;
    }
}

I liked the link from bruno-conde, which was a simpler one, but once I can't mark his comment as the answer, I'll mark Noldorin answer as the official, for it is a similar and satisfying answer.

Too bad there's not a way to prevent the code from compiling :(. Thanks, guys

Here's a better alternative as I have described at:

http://www.softwarerockstar.com/2010/10/..

Essentially it's a much simpler solution subclassing ReadOnlyCollection, which gets the work done in a more elegant manner.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top