Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Enable foreach for a class derived from Dictionary

I have a class derived from Dictionary. I need this class to simulate a HashSet, because Silverlight doesn't know HashSets and my classes make heavy use of HashSets. So I decided to exchange the HashSet with Dictionary. To further use my classes with all the HashSet-Objects, I try to make a custom HashSet class, that is derived from Dictionary and override all the relavant methods like the Add-method:

class HashSet<T> : Dictionary<T, object>
{

    public override void Add(T element)
    {
        base.Add(element, null);
    }
}

Now I need to enable the foreach-loop for my new HashSet-class. Obviously, my class returns a KeyValuePair in a foreach-loop, but I need T as return type. Can anyone tell me, what and how I need to override the Dictionary base class?

Thanks in advance, Frank

like image 704
Aaginor Avatar asked Nov 29 '22 06:11

Aaginor


1 Answers

I would strongly suggest that you don't derive from Dictionary in the first place. Use composition instead of inheritance. If you derive from Dictionary, people can use your class as a dictionary of key/value pairs instead of as a set.

So, you design your class with a dictionary inside it:

public sealed class DictionaryBackedSet<T> : IEnumerable<T>
{
    private readonly Dictionary<T, int> dictionary = new Dictionary<T, int>();

    public IEnumerator<T> GetEnumerator()
    {
        return dictionary.Keys.GetEnumerator();
    }

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

    public bool Add(T item)
    {
        if (Contains(item))
        {
            return false;
        }
        dictionary.Add(item, 0);
        return true;
    }

    public bool Contains(T item)
    {
        return dictionary.ContainsKey(item);
    }

    // etc
}

You might also want to create an empty struct as the value type argument for the dictionary:

public struct Empty {}

That may save a little memory. I wouldn't worry about it for now though - and if you compose the dictionary instead of inheriting from it, making that change later won't break anything :)

It would be nice if you could use System.Void for this purpose (i.e. use Dictionary<T, Void>), but C# won't let you do that :(

like image 164
Jon Skeet Avatar answered Dec 08 '22 05:12

Jon Skeet