views:

1259

answers:

8

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.

+3  A: 

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

Eoin Campbell
+4  A: 

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];
    }
}
Neil Barnwell
+1  A: 

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

arul
+8  A: 

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.)

Noldorin
+1 for "not posting the code here"! Linking to the original source is always better; akin to crediting the author.
Cerebrus
@Cerebrus: Yeah, one should always link to the original source first - as you say, it's best to attribute it to the author. My opinion is that if the code/text is short enough, it's usually helpful to *mirror* it here (in case the site goes down for example), but that's not really appropiate in this case.
Noldorin
Thank you for referencing my article :-).
Steven
A: 
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);
Tolgahan Albayrak
A: 

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;
    }
}
Tolgahan Albayrak
+1 for the simplicity of the solution, and for compatibility with the Dictionary's interfaces. However: Why using "new" instead of "override"? Further, besides the Add, the Remove method should be overridden, too.
chiccodoro
@chiccodoro: `Dictionary` does not have `virtual` methods.
SLaks
why was this downvoted? - @SLaks: allright
chiccodoro
A: 

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

Samuel Carrijo
A: 

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.

SoftwareRockstar