需要 IDictionary允许空键的实现

发布于 2024-08-15 06:25:05 字数 224 浏览 9 评论 0原文

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

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

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

Basically, I want something like this:

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

Are there any built into the base class library that allow this? The preceding code will throw an exception at runtime when adding the null key.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

两相知 2024-08-22 06:25:05

您可以避免使用 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");

如果您打算使集合具有更强的类型,则此方法将无法工作 - 比方说您希望键是字符串。由于字符串是密封的,因此您无法继承它来创建空值的“特殊值”替代品。您的选择会变得更加复杂。您可以:

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

顺便说一句,你的字典键真的需要键是object吗?由于在您可能希望将 Equals() 作为比较基础进行评估的情况下使用引用相等,这可能会导致微妙的错误。

You could avoid using null and create a special singleton value class that does the same thing. For example:

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");

This approach will fail to work if you intend to make your collection more strongly typed - let's say for example you want the key to be a string. Since string is sealed you can't inherit from it to create a "special value" substitute for null. Your alternatives become a bit more complicated. You could:

  1. Create some special constant value to represent the "empty" / "null" case. Kind of hacky and definitely a path to confusion. This can be a viable approach if the dictionary is completely private to some implementation class and you can write some Encode/Decode utility methods to avoid spreading the knowledge of how you translate keys all over the place.
  2. Create your own implementation of IDictionary that internally delegates to a Dictionary<> instance - except for the case of null. This violates the documented expectations for the IDictionary<> interface which does say that null keys should throw an exception. But you may be able to get away with it if it's the only way to solve your real problem. This only works if you own and create the dictionary instance.
  3. Find a way to solve your problem without storing a "null" key in the dictionary. For example, consider not populating the null key in the dictionary and having some special case logic to deal with it. Keys have to be hashable and comparable to work with the underlying implementation, which is why null is prohibited normally.

As an aside, does your dictionary key really need the key to be object? This can lead to subtle bugs due to reference equality being used where you may have intended Equals() to be evaluated as the basis for comparison.

番薯 2024-08-22 06:25:05

这个怎么样?

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

How about this?

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; }
        }
    }
}
还如梦归 2024-08-22 06:25:05

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
    }

}

NameValueCollection can take a null key but it does not implement IDictionary. It would however be pretty easy to derive from DictionaryBase and provide Add/Remove/Indexers etc that simply replace null with something built in like:

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

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

}
浅暮の光 2024-08-22 06:25:05

您可以简单地使用 ValueTuple 作为 key 的包装器,例如:

Dictionary<ValueTuple<string?>, string>

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

Dictionary<ValueTuple<string?>, string>
笑饮青盏花 2024-08-22 06:25:05

不需要不同的字典实现。

看看我在这里的回答:
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]);

No need for a different implementation of Dictionary.

Take a look at my answer here:
https://stackoverflow.com/a/22261282/212272

You will also be able to keep your dictionary strongly typed:

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]);
垂暮老矣 2024-08-22 06:25:05

如果键是枚举,您可以使用不存在的值而不是 null,如 (YourEnum)(-1)

If key is enum, you can use not existing value instead of null like (YourEnum)(-1)

孤云独去闲 2024-08-22 06:25:05

key 真的需要为 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);

Does the key literally need to be NULL? The key in the collection works out to be an index. It doesn't make a lot of sense to me to have NULL for an index in a collection.

Maybe create a new class


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);
一世旳自豪 2024-08-22 06:25:05

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

}

A slight variation on jestro's answer to make for a cleaner(to me) solution that makes it more explicit what you are trying to do. Obviously this could be extended as needed. But you get the picture, just make a wrapper.

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

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文