如何获得null而不是KeyNotFoundException通过键访问字典值?
在某些特定情况下,当在字典中没有这样的密钥时,通过密钥访问字典值时,对于我来说,使用KeyNotFoundException
可读的方式来获得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
字典字段的类,它暴露了我需要的function:
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
,如下所示:
Func<string, string> GetDictValueByKeyOrNull = (key) => { if (dict.ContainsKey(key)) return dict[key]; else return null; };
所以它可以像GetDictValueByKeyOrNull("key1")
。
请你给我更多的build议或帮助select一个更好的?
你不能用扩展方法得到你想要的语法,而像别人所说的重写方法/操作符来改变它的行为通常不是一个好主意。 我认为你能做的最好的就是缩短你使用的名字。
这就是如果你需要保持IDictionary接口。 如果你没有与任何需要一个IDictionary的代码进行交互,那么你可以自由定义你自己的接口并使[]运算符以不同的方式工作。
不pipe你最终调用这个函数,你都需要像这样实现它:
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。
这是我个人图书馆的解决scheme,作为扩展方法实施。 我只发布它,因为它是从字典界面实现,并允许传递一个可选的默认值。
履行
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();
最后,我想出了一个变体,使用从字典类派生的显式接口实现:
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; dict.TryGet(key, out val); return val; } } }
所以它公开了我需要的function如下:
//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");
我的前提是说我不会使用这个。 new
关键字,虽然在这种情况下很有用,但可能会产生很难find的错误。 除此之外,你可以尝试这个类。
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; } } }
值得指出的是,HybridDictionary默认是这样做的。 你失去了generics的types,但是得到了null-if-not-found的function。
而且(至less从理论上讲),我认为在价值低的情况下你可以获得性能上的好处。
添加一个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); } }
如果没有在字典中find键,它可以返回默认值 。
如果这是引用types,则默认值为null。
_dic.GetValueOrDefault();
我已经完成了这之前,它只是inheritance了常规的Dictionary类,只是隐藏索引器。 这样做非常干净,因此您可以自动获得Regular 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; } } }