0

I thought of solution below because the collection is very very small. But what if it was big?

private Dictionary<string, OfTable> _folderData = new Dictionary<string, OfTable>();

public Dictionary<string, OfTable> FolderData
{
    get { return new Dictionary<string,OfTable>(_folderData); }
}

With List you can make:

public class MyClass
{
    private List<int> _items = new List<int>();

    public IList<int> Items
    {
        get { return _items.AsReadOnly(); }
    }
}

That would be nice!

Thanks in advance, Cheers & BR - Matti

NOW WHEN I THINK THE OBJECTS IN COLLECTION ARE IN HEAP. SO MY SOLUTION DOES NOT PREVENT THE CALLER TO MODIFY THEM!!! CAUSE BOTH Dictionary s CONTAIN REFERENCES TO SAME OBJECT. DOES THIS APPLY TO List EXAMPLE ABOVE?

class OfTable
{
    private int _table;
    private List<int> _classes;
    private string _label;

    public OfTable()
    {
        _classes = new List<int>();
    }

    public int Table
    {
        get { return _table; }
        set { _table = value; }
    }

    public List<int> Classes
    {
        get { return _classes; }
        set { _classes = value; }
    }

    public string Label
    {
        get { return _label; }
        set { _label = value; }
    }
}

so how to make this immutable??

char m
  • 7,840
  • 14
  • 68
  • 117

2 Answers2

4

It's not difficult to roll your own ReadOnlyDictionary<K,V> wrapper class. Something like this:

public sealed class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    private readonly IDictionary<TKey, TValue> _dictionary;

    public ReadOnlyDictionary(IDictionary<TKey, TValue> dictionary)
    {
        if (dictionary == null)
            throw new ArgumentNullException("dictionary");

        _dictionary = dictionary;
    }

    public bool ContainsKey(TKey key)
    {
        return _dictionary.ContainsKey(key);
    }

    public int Count
    {
        get { return _dictionary.Count; }
    }

    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
    {
        return _dictionary.GetEnumerator();
    }

    public ICollection<TKey> Keys
    {
        get { return _dictionary.Keys; }
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        return _dictionary.TryGetValue(key, out value);
    }

    public ICollection<TValue> Values
    {
        get { return _dictionary.Values; }
    }

    public TValue this[TKey key]    // Item
    {
        get { return _dictionary[key]; }
    }

    #region IDictionary<TKey, TValue> Explicit Interface Implementation

    void IDictionary<TKey, TValue>.Add(TKey key, TValue value)
    {
        throw new NotSupportedException("Dictionary is read-only.");
    }

    bool IDictionary<TKey, TValue>.Remove(TKey key)
    {
        throw new NotSupportedException("Dictionary is read-only.");
    }

    TValue IDictionary<TKey, TValue>.this[TKey key]    // Item
    {
        get { return _dictionary[key]; }
        set { throw new NotSupportedException("Dictionary is read-only."); }
    }

    #endregion

    #region ICollection<T> Explicit Interface Implementation

    void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item)
    {
        throw new NotSupportedException("Collection is read-only.");
    }

    void ICollection<KeyValuePair<TKey, TValue>>.Clear()
    {
        throw new NotSupportedException("Collection is read-only.");
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.Contains(KeyValuePair<TKey, TValue> item)
    {
        return _dictionary.Contains(item);
    }

    void ICollection<KeyValuePair<TKey, TValue>>.CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
    {
        _dictionary.CopyTo(array, arrayIndex);
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.IsReadOnly
    {
        get { return true; }
    }

    bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item)
    {
        throw new NotSupportedException("Collection is read-only.");
    }

    #endregion

    #region IEnumerable Explicit Interface Implementation

    IEnumerator IEnumerable.GetEnumerator()
    {
        return ((IEnumerable)_dictionary).GetEnumerator();
    }

    #endregion
}

If you're using C#3 or later then you could knock-up a matching AsReadOnly extension method too:

public static class ReadOnlyDictionaryHelper
{
    public static ReadOnlyDictionary<TKey, TValue> AsReadOnly<TKey, TValue>(this IDictionary<TKey, TValue> dictionary)
    {
        var temp = dictionary as ReadOnlyDictionary<TKey, TValue>;
        return temp ?? new ReadOnlyDictionary<TKey, TValue>(dictionary);
    }
}

And then return the read-only wrapper from your property:

// in C#2
return new ReadOnlyDictionary<string, OfTable>(_folderData);

// in C#3 or later
return _folderData.AsReadOnly();
LukeH
  • 263,068
  • 57
  • 365
  • 409
  • thanks! yes, that is true. lots of code... i saw similar implementation here in StackOverflow. I gave u 1 up, but making a wrapper is not what I want. sorry 'bout being picky. if nobody can give answer with shorter code i accept it. cheers mate! – char m Apr 07 '10 at 10:02
  • @matti: Yes a lot of code, but see other answer: this is now done for you in the framework, and even in downlevel versions this is fully reusable code so you only need to write it once. – Richard Apr 07 '10 at 10:09
  • threre is a problem: the objects contained can be changed. but there is maybe nothing to do about. it would be nice that both collection and objects inside would be readonly... i'm not making a code library, but only a simple program so any of this doesn't really matter. I just wanna learn... – char m Apr 07 '10 at 10:12
  • @matti: There's not really any straightforward way of preventing changes to the objects stored in the dictionary (assuming that they're reference types). If they're your own custom objects (eg, `OfTable`) then perhaps you could consider making them immutable. – LukeH Apr 07 '10 at 10:21
  • thanks luke! I add the code for OfTable so can you plase tell me how to make it immutable (10 parts of this http://blogs.msdn.com/ericlippert/archive/2007/11/13/immutability-in-c-part-one-kinds-of-immutability.aspx is too much) – char m Apr 07 '10 at 10:30
  • @matti: Unfortunately there's no easy, generally applicable answer to making it immutable. Well, I could suggest that you remove all the property setters and make the `Classes` property return a `ReadOnlyCollection` rather than `List`, but that will almost certainly break your existing code. Making `OfTable` immutable will require changes - possibly major changes - throughout your code. – LukeH Apr 07 '10 at 10:47
1

Use ReadOnlyCollection<T> class.

An instance of the ReadOnlyCollection generic class is always read-only. A collection that is read-only is simply a collection with a wrapper that prevents modifying the collection; therefore, if changes are made to the underlying collection, the read-only collection reflects those changes. See Collection for a modifiable version of this class.

--EDIT--

Checkout a trivial dictionary wrapper here. And A Generic Read-Only Dictionary by Richard Carr.

Community
  • 1
  • 1
KMån
  • 9,896
  • 2
  • 31
  • 41