如何获得空,而不是KeyNotFoundException访问字典值的关键
本文关键字:字典 访问 KeyNotFoundException 何获得 | 更新日期: 2023-09-27 17:50:32
在某些情况下,当字典中没有这样的键时,有一个简短的,可读的方式来获取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
:
Func<string, string> GetDictValueByKeyOrNull = (key) =>
{
if (dict.ContainsKey(key))
return dict[key];
else
return null;
};
所以它可以像GetDictValueByKeyOrNull("key1")
一样被利用。
你能给我更多的建议或帮助我选择一个更好的吗?
这是我个人库的解决方案,作为扩展方法实现。我只是发布它,因为它是从字典接口实现的,并允许一个可选的默认值传入。
实施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 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次。
最后我想出了一个变体,使用一个派生自字典类的显式接口实现:
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");
添加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();
值得指出的是,HybridDictionary在默认情况下会这样做。您失去了泛型类型,但获得了null-if-not-found功能。
我的前提是我将不使用这个。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; }
}
}
我以前这样做过,它很好地继承了常规的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;
}
}
}