An Elegant Way to Implement ReadOnlyDictionary(TKey, TValue) in C#

October 30th, 2010 Leave a comment Go to comments

While working on creating an application framework for a personal project, I needed a way to expose a Dictionary<TKey, TValue> object from one of my methods. The only caveat being, I wanted the Dictionary object to be read-only.

I knew that there exists a ReadOnlyCollection<T> in the FCL, but to my dismay there is no built-n way of creating a read-only Dictionary in .NET.  I searched the web to see how other people are solving this problem, but didn’t find a suitable implementation that I was happy with.  Hence I created a nice little ReadOnlyDictionary<TKey, TValue> that essentially allows developers to expose an immutable Dictionary object of specified key and value types.

public sealed class ReadOnlyDictionary < TKey, TValue > : ReadOnlyCollection < KeyValuePair < TKey, TValue > >
{
    public ReadOnlyDictionary(IDictionary<tkey , TValue> items)
        : base(items.ToList()) { }

    public TValue this[TKey key]
    {
        get
        {
            var valueQuery = GetQuery(key);
            if (valueQuery.Count() == 0)
                throw new NullReferenceException("No value found for given key");
            
            return valueQuery.First().Value;
        }
    }

    public bool ContainsKey(TKey key)
    {
        return (GetQuery(key).Count() > 0);
    }

    public bool TryGetValue(TKey key, out TValue value)
    {
        var toReturn = ContainsKey(key);
        value = toReturn ? this[key] : default(TValue);
        return toReturn;
    }

    private IEnumerable < KeyValuePair < TKey, TValue > > GetQuery(TKey key)
    {
        return (from t in base.Items where t.Key.Equals(key) select t);
    }
}

As you can see the class itself is very concise. This is because it cleverly derives from ReadOnlyCollection<KeyValuePair<TKey, TValue>>, and only adds two methods and an indexer.  Also it uses LINQ to Objects to select Dictionary items, and the LINQ query is neatly tucked in a private method where it’s re-used from other public methods.

 

Comment moderation is enabled. Your comment may take some time to appear.