Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Strange behavior of indexer in custom Dictionary

I have made a custom Dictionary class which inherits from Dictionary. However, strange things happen when calling the indexer depending on how I use the class. Here's a simplified version of the class:

public class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            return base[key];
        }
        set
        {
            base[key] = value;
        }
    }
}

Now, I want to create an instance and add something to it. The following works fine, i.e. I can set a breakpoint in the setter of the indexer and it will be hit.

MyDictionary<int, string> dict = new MyDictionary<int, string>();
dict[0] = "some value";

However, if I do it like this (instantiate into an IDictionary variable):

IDictionary<int, string> dict = new MyDictionary<int, string>();
dict[0] = "some value";

it will no longer hit my breakpoint in the setter of the indexer, i.e. it must be calling something else. If I take a look at .NET's Dictionary implementation (from which my class inherit) I can find no other indexer than the one I override, and it doesn't inherit from anything else. So the question is, what is going on?

like image 682
maze_dk Avatar asked Dec 21 '22 08:12

maze_dk


1 Answers

The point is in the new keyword in your indexer declaration. This doesn't override base class indexer and every time you access indexer from a base class or interface (like IDictionary in your example) - indexer of a base class would be called. Moreover, you can't override base class indexer, because it doesn't marked as virtual in Dictionary<TKey, TValue> class definition

consider this article on new modifier in method declaration

Try to use composition here, instead of inheritance.

If you are sure, that you need custom behavior for exactly IDictionary<TKey, TValue and not more abstract interfaces, like ICollection<KeyValuePair<TKey, TValue>> or even IEnumerable<KeyValuePair<TKey, TValue>>, use next example:

public class MyDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
    IDictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();

    //LOTS of other methods here, that are required by IDictionary<TKey, TValue>
    //their implementation would be delegation to dictionary instance

    public TValue this[TKey key] //implementation of a interface
    {
        get
        {
            return dictionary[key];
        }
        set
        {
            dictionary[key] = value;
        }
    }
}
like image 74
Ilya Ivanov Avatar answered Jan 07 '23 23:01

Ilya Ivanov