C# - 需要一个允许空键的IDictionary实现

时间:2009-12-16 18:50:26

标签: c# collections idictionary

基本上,我想要这样的东西:

Dictionary<object, string> dict = new Dictionary<object, string>();
dict.Add(null, "Nothing");
dict.Add(1, "One");

基类库中是否有允许这样做的内容?添加空键时,上面的代码将在运行时抛出异常。

由于

6 个答案:

答案 0 :(得分:11)

您可以避免使用null并创建一个执行相同操作的特殊单例值类。例如:

public sealed class Nothing
{ 
  public static readonly Nothing Value = new Nothing(); 
  private Nothing() {}
}

Dictionary<object, string> dict = new Dictionary<object, string>();
dict.add(Nothing.Value, "Nothing");
dict.add(1, "One");

如果您打算使您的集合更强类型,这种方法将无法工作 - 例如,您希望密钥是字符串。由于字符串是密封的,因此您无法继承它以创建“特殊值”替代null。你的选择变得有点复杂。你可以:

  1. 创建一些特殊的常量值来表示“空”/“空”的情况。有点hacky,绝对是混乱的途径。如果字典对于某些实现类是完全私有的,那么这可能是一种可行的方法,您可以编写一些Encode / Decode实用程序方法,以避免传播有关如何在整个位置翻译密钥的知识。
  2. 创建自己的IDictionary实现,内部委托给Dictionary&lt;&gt;实例 - 除了null的情况。这违反了对IDictionary&lt;&gt;的记录期望。接口,它确实说空键应该抛出异常。但是,如果这是解决您真正问题的唯一方法,那么您可以逃脱它。这仅在您拥有并创建字典实例时才有效。
  3. 找到一种解决问题的方法,而无需在字典中存储“null”键。例如,考虑不在字典中填充null键并使用一些特殊的案例逻辑来处理它。密钥必须是可清除的,并且与底层实现相当,这就是通常禁止null的原因。
  4. 顺便说一下,你的词典密钥真的需要密钥object吗?这可能会导致细微的错误,因为您可能希望将Equals()作为比较的基础来使用引用相等。

答案 1 :(得分:5)

这个怎么样?

public class NullableDictionnary<T1, T2> : Dictionary<T1, T2>
{
    T2 null_value;

    public T2 this[T1 key]
    {
        get
        {
            if (key == null)
            { return null_value; }
            return base[key];
        }
        set
        {
            if (key == null)
            { null_value = value; }
            else
            { base[key] = value; }
        }
    }
}

答案 2 :(得分:2)

NameValueCollection可以采用null键,但它不实现IDictionary。然而,很容易从DictionaryBase派生并提供添加/删除/索引器等,只需将null替换为内置的内容,如:

class MyDictionary : DictionaryBase {
    private readonly object nullKey = new object();

    void Add(object key, string value) {
       if ( key == null ) { key = nullKey; }
       .. call base methods
    }

}

答案 3 :(得分:0)

密钥字面上是否需要为NULL?集合中的关键是索引。对于集合中的索引具有NULL,对我来说没有多大意义。

也许创建一个新类


public class ObjectEntry
{
    public object objRef;
    public string desc;

    public ObjectEntry(object objectReference)
    {
        objRef = objectReference;
        if (objRef = null) {desc = "Nothing";}
        else {desc = objRef.Description;} //or whatever info you can get from a proper objRef value
    }
}

newObj = new ObjectEntry(null);
dict.add(newObj, newObj.desc);

答案 4 :(得分:0)

无需对Dicionary进行不同的实施。

看看我的回答: https://stackoverflow.com/a/22261282/212272

您还可以保持字典强力输入:

var dict = new Dictionary<NullObject<int?>, string>();
dict[1] = "one int";
dict[null] = "null int";

Assert.AreEqual("one int", dict[1]);
Assert.AreEqual("null int", dict[null]);

答案 5 :(得分:0)

jestro的答案略有不同,以寻求更清洁的解决方案(对我而言),从而使您更清楚地了解您要做什么。显然,这可以根据需要扩展。但是,您得到图片后,只需包装一下即可。

public class NullDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    private TValue _default;
    public new TValue this[TKey key]
    {
        get { 
            if(key == null)
            {
                return _default;
            }
            return _decorated[key];
        }
    }
    private Dictionary<TKey, TValue> _decorated;
    public NullDictionary( Dictionary<TKey,TValue> decorate, TValue defaultValue = default)
    {
        _decorated = decorate;
        _default = defaultValue;
    }    

}