我目前在我的项目中有很多Dictionary<string, T>
用途,其中大部分看起来像这样:
if (myDic.ContainsKey("some key"))
localVar = myDic["some key"];
它也不是很有效,因为它对字典进行了两次调用,这可能会消耗资源。TryGetValue()
是一件很酷的事情,但它并不是在一条线上完成的。
我只想null
从var v = myDic[key]
. 我怎么做?
我目前在我的项目中有很多Dictionary<string, T>
用途,其中大部分看起来像这样:
if (myDic.ContainsKey("some key"))
localVar = myDic["some key"];
它也不是很有效,因为它对字典进行了两次调用,这可能会消耗资源。TryGetValue()
是一件很酷的事情,但它并不是在一条线上完成的。
我只想null
从var v = myDic[key]
. 我怎么做?
您可以使用扩展方法TryGetValue
:
public static U GetValueByKeyOrNull<T, U>(this Dictionary<T, U> dict, T key)
where U : class
{
U value;
dict.TryGetValue(key, out value);
return value;
}
多亏了它,你才能写
somedict.GetValueByKeyOrNull("key1")
最后试图做这件事,我想出了一个变体,使用从字典类派生的具有显式接口实现的变体:如何获取 null 而不是 KeyNotFoundException 按键访问字典值?
那是
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;
}
}
}
并在任何地方使用它而不是原始字典:
//create some dictionary
NullValueDictionary<int, string> dict = new NullValueDictionary<int, string>
{
{1,"one"}
};
//have a reference to the interface
INullValueDictionary<int, string> idict = dict;
string val = idict[2]; // null
val = idict[1]; // "one"
我不喜欢处理,null
所以我的实现将如下所示:
interface Maybe<T> {
bool HasValue {get;}
T Value {get;}
}
class Nothing<T> : Maybe<T> {
public bool HasValue { get { return false; } }
public T Value { get { throw new Exception(); } }
public static const Nothing<T> Instance = new Nothing<T>();
}
class Just<T> : Maybe<T> {
private T _value;
public bool HasValue { get { return true; } }
public T Value { get { return _value; } }
public Just(T val) {
_value = val;
}
}
Maybe
是一个可以包含值或不包含值的对象。请注意,Nothing
类包含静态字段Instance
。我们可以使用这个值而不是每次需要Nothing
从函数返回时创建新值。
现在,我们需要创建自己的字典类:
class MyDictionary<TKey, TValue>
{
private Dictionary<TKey, TValue> _dict;
...
public Maybe<TValue> this[TKey key] {
TValue val;
if (_dict.TryGetValue(key, out val)) {
return new Just<TValue>(val);
return Nothing<TValue>.Instance;
}
}
这种方法的优势尚不清楚,因为 C# 没有模式匹配。但它可以用以下方式模拟dynamic
:
void ProcessResult(Just<string> val) {
Console.WriteLine(val);
}
void ProcessResult(Nothing<string> n) {
Console.WriteLine("Key not found");
}
var dict = new MyDictionary<string, string>();
...
dynamic x = dict["key"];
ProcessResult(x);
我认为这是表达字典不能总是返回有意义的结果这一事实的非常清晰的方式。同样对于读者来说很明显,函数重载ProcessResult(Just<T>)
只会为字典中存在的值调用,而其他重载将在未找到键的情况下调用。
优点:
缺点:
我决定这样做:
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; }
}
}
它让我可以像使用任何其他字典一样通过方括号使用它。由于我不会将它与值类型一起使用 as TValue
,因此我认为这是一个足够好的解决方案。