【问题标题】:How to correctly implement the IDictionary interface and subclass from it如何正确实现 IDictionary 接口及其子类
【发布时间】:2017-01-25 03:32:44
【问题描述】:

我的目标是拥有一个具有唯一键 值的字典,我正在使用一个额外的 HashSet 来解决这个问题。我想有一个基类,更具体的类型从中继承。

据我了解,字典类的 add-Method 不是虚拟的,因此不能被覆盖。所以这样做的唯一方法是实现 IDictionary 接口。

所以我的字典基类的基本结构是:

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
}

现在我想要一个具体的子类,它以 ints 作为键,string 作为值:

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
        }
    }
}

在这里我遇到了各种各样的问题。 第一个是The best overloaded method match for 'System.Collections.Generic.Dictionary&lt;int,string&gt;.ContainsKey(string) has some invalid arguments'. Cannot convert type 'TKey' to 'string'. 同意。所以我将InternalDict 更改为new Dictionary&lt;TKey,short&gt;() 并将Add 的参数更改为(TKey key, TValue value)

下一个问题是如何访问方法。假设我的实现如下所示:

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;
}

如果我通过1,这个GetValue 方法总是抛出实现的异常,我真的不明白为什么。我调试了代码,可以看出“InternalDict”实际上确实保存了键 1 和值 foobar. TheTryGetValuecall onmyDictjumps into the implementation of theBaseCustomDictionaryclass and writes an empty string into thevalue` 变量。

当然,我现在可以在我的子类中实现我自己的TryGetValue,但如果我必须实现每个方法,这似乎违背了拥有子类的目的。

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

我觉得我在继承方面做错了什么。

【问题讨论】:

    标签: c# dictionary inheritance idictionary


    【解决方案1】:

    子类没有理由是泛型的;它存在的原因是为其基类指定类型参数。像这样声明子类:

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

    如果您的基类不是抽象的,则您不需要为此实现任何成员。事实上,我不清楚为什么你不只是实例化BaseCustomDictionary&lt;int, String&gt;,就像你对Dictionary 所做的那样,但是有充分的理由来进行子类化,这与你的问题无关。

    顺便说一句,通用基础中的 this 不会编译:

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

    这将 -- value 参数需要是 TValue。但我猜这只是撰写问题时的复制和粘贴错误。

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

    【讨论】:

      【解决方案2】:

      你做错事了:

      公共类 IntStringDictionary:BaseCustomDictionary

      要创建与BaseCustomDictionary 具有相同功能的 int 字符串字典,您不要继承。你只需这样做:

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

      就这么简单!

      仅当您想向BaseCustomDictionary 添加新功能时才继承。根据您的问题,我看不出您要向BaseCustomDictionary 添加什么新行为。

      【讨论】:

      • 主要是'Add`方法。根据我的值的类型,我将调用不同的方法来生成伪随机值。否则我不知道如何在 BaseCustomDictionary 类中添加这种差异化。
      • 对不起,我没有注意到 Add 方法。但是您的 Add 方法实现似乎很奇怪。我认为您应该将该逻辑留给字典类的用户。另一种方法是向 BaseCustomDictionary 添加扩展方法。
      猜你喜欢
      • 1970-01-01
      • 2022-01-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-06-10
      • 2015-05-12
      • 2016-02-15
      • 2012-10-24
      相关资源
      最近更新 更多