0

My goal is to have a dictionary that has unique keys and values, which I'm solving with an additional HashSet. I want to have a base class from which more specific types inherit from.

As I have understood, the add-Method of the dictionary class is not virtual, thus cannot be overriden. So the only way to do so, is to implement the IDictionary interface.

So the basic structure of my base dictionary class is:

public class BaseCustomDictionary<TKey,TValue>:IDictionary<TKey,TValue> {
    public virtual Dictionary<TKey,TValue> InternalDict {
        get;
        set;
    }

    public BaseCustomDictionary() {
        this.InternalDict = new Dictionary<TKey,TValue>();
    }

    // Here I start implementing all the required methods, e.g. Add, TryGetValue
    public virtual void Add(TKey key, TValue value) {
        InternalDict.Add( key, value );
    }

    public bool TryGetValue (TKey key, out string value) {
        return InternalDict.TryGetValue (key, out value);
    }

    // And so on and so forth
}

Now I want to have a concrete subclass that has ints as keys and string as values:

public class IntStringDictionary<TKey,TValue>:BaseCustomDictionary<TKey,TValue> {
    public override Dictionary<int,string> InternalDict {
        get;
        set;
    }

    HashSet<string> UniqueValues;

    public IntStringDictionary() {
        InternalDict = new Dictionary<int,string>();
        UniqueValues = new HashSet<string>();
    }

    public override void Add (TKey key, TValue value) {
        if (InternalDict.ContainsKey (key)) {
            return;
        }

        string randomStr = RandomString();

        if (!UniqueValues.Add(randomStr)) {
            Add(key,value);
            return;
        } else {
            InternalDict.Add(key,randomStr);
            return
        }
    }
}

Here I run into all sorts of problems. First one is The best overloaded method match for 'System.Collections.Generic.Dictionary<int,string>.ContainsKey(string) has some invalid arguments'. Cannot convert type 'TKey' to 'string'. Agree. So I change the InternalDict to new Dictionary<TKey,short>() and the parameters for Add to (TKey key, TValue value).

The next problem is how methods are accessed. Say my implementation looks like this:

public static IntStringDictionary<int,string> myDict = new IntStringDictionary<int,string>();

// Assuming the class is named Constructor
public Constructor() {
    myDict.Add(1,"foobar");
}

public static string GetValue (int key) {
    string value;
    myDict.TryGetValue(key, out value);

    if (value == '') {
        throw new NullReferenceException ("Value not found for given key");
    }

    return value;
}

This GetValue method always throws the implemented exception if I pass 1, and I don't really understand why. I debugged the code and can tell that the 'InternalDict' does in fact hold the key 1 and the value foobar. TheTryGetValuecall onmyDictjumps into the implementation of theBaseCustomDictionaryclass and writes an empty string into thevalue` variable.

Of course I could now implement my own TryGetValue in my subclass, but that seems to defeat the purpose of having subclasses, if I have to implement every method.

public bool TryGetValue(TKey key, out int value) {
    return InternalDict.TryGetValue(key, out value);
}

I feel like I'm doing something fundamentally wrong with the inheritance.

ShitakeOishii
  • 89
  • 2
  • 9

2 Answers2

0

The subclass has no reason to be generic; its reason for being is to specify type parameters for its base class. Declare the subclass like this:

public class IntStringDictionary : BaseCustomDictionary<int,String> 
{
}

You shouldn't need to implement any members for that, if your base class isn't abstract. In fact it's not clear to me why you're not just instantiating BaseCustomDictionary<int, String>, as you would with Dictionary, but there are valid reasons to subclass that wouldn't be relevant to your question.

Incidentally, this in the generic base won't compile:

public bool TryGetValue (TKey key, out string value) {
    return InternalDict.TryGetValue (key, out value);
}

This will -- the value parameter needs to be TValue. But I'm guessing this was merely a copy and paste error in composing your question.

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

You're doing things wrongly since this:

public class IntStringDictionary:BaseCustomDictionary

To create a int string dictionary that has the same functionality as a BaseCustomDictionary, you do not inherit. You just do:

var myDict = new BaseCustomDictionary<int, string>();

Simple as that!

You only inherit when you want add new functionality to BaseCustomDictionary. From your question, I cannot see what new behaviour you want to add to your BaseCustomDictionary.

Sweeper
  • 213,210
  • 22
  • 193
  • 313
  • It's mainly the 'Add` method. Depending on the type of my values, I will call a different method to generate a pseudo-random value. Else I don't know how I could add that differentiation in the `BaseCustomDictionary` class. – ShitakeOishii Jan 24 '17 at 18:56
  • Sorry I didn't notice the Add method. But your Add method implementation seems weird. I think you should leave that logic to the user of the dictionary class. Another way is to add extension methods to the BaseCustomDictionary. – Sweeper Jan 24 '17 at 19:07