17

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

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

是否有任何内置的基类库允许这样做?上述代码在添加空键时会在运行时抛出异常。

4

7 回答 7

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. 创建一些特殊的常量值来表示“空”/“空”的情况。有点骇人听闻,绝对是通往混乱的道路。如果字典对某些实现类完全私有,并且您可以编写一些 Encode/Decode 实用程序方法来避免将您如何翻译密钥的知识传播到各处,这可能是一种可行的方法。
  2. 创建您自己的 IDictionary 实现,该实现在内部委托给 Dictionary<> 实例 - 除了 null 的情况。这违反了对 IDictionary<> 接口的记录期望,该接口确实说空键应该引发​​异常。但是,如果这是解决您真正问题的唯一方法,您也许可以侥幸逃脱。这仅在您拥有并创建字典实例时才有效。
  3. 找到一种方法来解决您的问题,而无需在字典中存储“空”键。例如,考虑不填充字典中的空键并使用一些特殊情况逻辑来处理它。密钥必须是可散列的并且可以与底层实现进行比较,这就是通常禁止 null 的原因。

顺便说一句,您的字典键真的需要键object吗?由于在您可能打算将 Equals() 评估为比较基础的地方使用了引用相等,这可能会导致细微的错误。

于 2009-12-16T18:57:51.450 回答
4

这个怎么样?

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; }
        }
    }
}
于 2009-12-16T19:08:48.730 回答
1

NameValueCollection 可以采用空键,但它不实现 IDictionary。然而,从 DictionaryBase 派生并提供 Add/Remove/Indexers 等将非常容易,只需将 null 替换为内置的内容,例如:

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

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

}
于 2009-12-16T19:00:42.070 回答
1

不需要字典的不同实现。

看看我的答案: 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]);
于 2014-03-07T21:50:35.077 回答
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);
于 2009-12-16T19:10:38.123 回答
0

You can simply use ValueTuple as a wrapper for key, for example:

Dictionary<ValueTuple<string?>, string>
于 2021-09-12T02:40:18.713 回答
-1

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

}
于 2020-05-13T16:04:08.787 回答