Lenny
Lenny

Reputation: 155

C# overriding method

I need help with overriding method IEnumerator<T>. I want to have a dictionary class that during enumeration will return only elements, like dictionary.Values. It work in foreach, I suggest that because foreach use IEnumerator instead of IEnumerator<T>, but LINQ methods not work over instances of my class. If I try call linq method I get Could not find an implementation of the query pattern for source type. 'Where' not found.

public abstract class SpecialDictionary : Dictionary<TKey, MyClass>, IEnumerable<MyClass>
{
    public Add(MaClass item)
    {
        Add(item.Id, item); 
    }

    new public IEnumerator<MyClass> GetEnumerator()
    {
        return this.Values.GetEnumerator();
    }

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

I need collection of items with fast access to element by id. All elements have Guid id. This seemed like a good idea for me, but I welcome your suggestions of this solutions.

Upvotes: 3

Views: 195

Answers (1)

Marc Gravell
Marc Gravell

Reputation: 1062492

The problem is that SpecialDictionary now implements both IEnumerable<KeyValuePair<Guid,MyClass>> and IEnumerable<MyClass>. Because of this ambiguity, LINQ is unable to choose between these two options, and chooses neither. The extension methods still work, but require explicit type parameters:

MyClass item = dict.First<MyClass>();

and equally:

KeyValuePair<Guid, MyClass> pair = dict.First<KeyValuePair<Guid, MyClass>>();

LINQ, however, will not allow you to add explicit type parameters, so will not work. My advice: don't do that. If the user wants to work over the values, let them do so via .Values.


Here's an example of encapsulation:

public class SpecialDictionary : IEnumerable<MyClass>
{
    private readonly Dictionary<Guid, MyClass> inner = new Dictionary<Guid, MyClass>();
    public void Add(MyClass item)
    {
        inner.Add(item.Id, item);
    }

    public MyClass this[Guid id]
    {
        get { return inner[id]; }
        set { inner[id] = value; }
    }
    public bool TryGetValue(Guid id, out MyClass value)
    {
        return inner.TryGetValue(id, out value);
    }
    public IEnumerator<MyClass> GetEnumerator()
    {
        return inner.Values.GetEnumerator();
    }
    public int Count { get { return inner.Count; } }

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

Upvotes: 3

Related Questions