96

null在某些特定情况下,当字典中没有这样的键时,使用一种简短易读的方式来获取而不是KeyNotFoundException通过键访问字典值时对我来说似乎很有用。

我首先想到的是一个扩展方法:

public static U GetValueByKeyOrNull<T, U>(this Dictionary<T, U> dict, T key)
        where U : class //it's acceptable for me to have this constraint
{
    if (dict.ContainsKey(key))
        return dict[key];
    else 
        //it could be default(U) to use without U class constraint
        //however, I didn't need this.
        return null; 
}

但实际上并不是很简短,当你写这样的东西时:

string.Format("{0}:{1};{2}:{3}",                                                 
              dict.GetValueByKeyOrNull("key1"),
              dict.GetValueByKeyOrNull("key2"),
              dict.GetValueByKeyOrNull("key3"),
              dict.GetValueByKeyOrNull("key4"));

我会说,最好有一些接近基本语法的东西:dict["key4"].

然后我想出了一个想法,创建一个带有private字典字段的类,它暴露了我需要的功能:

public class MyDictionary<T, U> //here I may add any of interfaces, implemented
                                //by dictionary itself to get an opportunity to,
                                //say, use foreach, etc. and implement them
                                // using the dictionary field.
        where U : class
{
    private Dictionary<T, U> dict;

    public MyDictionary()
    {
        dict = new Dictionary<T, U>();
    }

    public U this[T key]
    {
        get
        {
            if (dict.ContainsKey(key))
                return dict[key];
            else
                return null;
        }
        set
        {
            dict[key] = value;
        }
    }
}

但是,基本行为的细微变化似乎有点开销。

另一种解决方法可能是Func在当前上下文中定义 a ,如下所示:

Func<string, string> GetDictValueByKeyOrNull = (key) =>
{
    if (dict.ContainsKey(key))
        return dict[key];
    else
        return null;
};

所以它可以像GetDictValueByKeyOrNull("key1").

请你给我更多的建议或帮助我选择一个更好的吗?

4

7 回答 7

84

这是我个人库中的解决方案,作为扩展方法实现。我只是发布它,因为它是从字典接口实现的,并且允许传入可选的默认值。

执行

public static TV GetValue<TK, TV>(this IDictionary<TK, TV> dict, TK key, TV defaultValue = default(TV))
{
    TV value;
    return dict.TryGetValue(key, out value) ? value : defaultValue;
}

用法

 MyDictionary.GetValue("key1");
 MyDictionary.GetValue("key2", -1);
 MyDictionary.GetValue("key3")?.SomeMethod();
于 2015-10-19T20:18:32.047 回答
36

您无法使用扩展方法获得所需的语法,并且正如其他人所说,重写方法/运算符以更改其行为通常不是一个好主意。我认为你能做的最好的就是缩短你使用的名字。

那就是如果您需要保留 IDictionary 界面。如果您没有与任何需要 IDictionary 的代码交互,那么您可以自由定义自己的接口,并且让 [] 运算符以不同的方式工作不是问题。

无论您最终调用该函数,您都希望像这样实现它:

public static U Get<T, U>(this Dictionary<T, U> dict, T key)
    where U : class
{
    U val;
    dict.TryGetValue(key, out val);
    return val;
}

它只进行一次查找,而您的实现则需要 2 次。

于 2013-01-04T16:24:36.643 回答
27

最后,我想出了一个变体,使用从字典类派生的具有显式接口实现的变体:

public interface INullValueDictionary<T, U>
    where U : class
{
    U this[T key] { get; }
}

public class NullValueDictionary<T, U> : Dictionary<T, U>, INullValueDictionary<T, U>
    where U : class
{
    U INullValueDictionary<T, U>.this[T key]
    {
        get
        {
            U val;
            this.TryGetValue(key, out val);
            return val;
        }
    }
}

因此,它通过以下方式公开了我需要的功能:

//create some dictionary
NullValueDictionary<int, string> dict = new NullValueDictionary<int, string>
{
    {1,"one"}
};
//have a reference to the interface
INullValueDictionary<int, string> idict = dict;

try
{
    //this throws an exception, as the base class implementation is utilized
    Console.WriteLine(dict[2] ?? "null");
}
catch { }
//this prints null, as the explicit interface implementation 
//in the derived class is used
Console.WriteLine(idict[2] ?? "null");
于 2013-01-04T04:54:48.010 回答
19

添加DictionaryExtension班级

public static class DictionaryExtension
{
    public static TValue GetValueOrDefault<TKey, TValue>
        (   this IDictionary<TKey, TValue> dictionary,TKey key)
    {
        TValue value;
        return dictionary.TryGetValue(key, out value) ? value : default(TValue);
    }
}

如果在字典中找不到键,它可以返回默认值。

默认是null如果这是引用类型。

_dic.GetValueOrDefault();
于 2017-03-31T05:41:47.550 回答
7

值得指出的是HybridDictionary默认执行此操作。您失去了通用类型,但获得了 null-if-not-found 功能。

而且(至少在理论上)我认为,您可以在较少的值下获得性能优势。

于 2013-11-17T11:48:32.140 回答
5

我的前提是我不会使用它。该new关键字虽然在这种情况下很有用,但会产生很难找到的错误。除此之外,你可以试试这门课。

class MyDictionary<TKey, TValue> : Dictionary<TKey, TValue>
{
    public new TValue this[TKey key]
    {
        get
        {
            TValue value;
            return TryGetValue(key, out value) ? value : default(TValue);
        }
        set { base[key] = value; }
    }
}
于 2013-01-04T03:26:25.703 回答
0

我以前做过这个,它很好地继承了常规的 Dictionary 类并隐藏了索引器。这样做真的很干净,因此您会自动获得常规字典类的所有可靠性和熟悉度。

public class NullSafeDict<TKey, TValue> : Dictionary<TKey, TValue> where TValue : class
{
    public new TValue this[TKey key]
    {
        get
        {
            if (!ContainsKey(key))
                return null;
            else
                return base[key];
        }
        set
        {
            if (!ContainsKey(key))
                Add(key, value);
            else
                base[key] = value;
        }
    }
}
于 2016-04-16T00:30:10.613 回答