在某些情况下,当没有这样的情况时,按键访问字典值时,使用简短的,可读的方式来获取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")
一样使用。
请你再给我一些建议或帮助我选择更好的建议吗?
答案 0 :(得分:49)
以下是我个人图书馆的解决方案,作为扩展方法实施。我只发布它,因为它是从字典 interface 实现的,并允许传入可选的默认值。
<强>实施强>
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();
答案 1 :(得分:31)
您无法使用扩展方法获得所需的语法,并且正如其他人所说,重写方法/运算符以更改其行为通常不是一个好主意。我认为你能做的最好就是缩短你使用的名字。
如果你需要保持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次。
答案 2 :(得分:22)
最后,我想出了一个变体,它使用了一个带有显式接口实现的字典类派生:
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;
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");
答案 3 :(得分:10)
添加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();
答案 4 :(得分: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; }
}
}
答案 5 :(得分:2)
值得指出HybridDictionary默认执行此操作。 您丢失了泛型类型,但获得了null-if-not-found功能。
并且(至少在理论上)我认为,在数量较少的情况下,您可以获得性能优势。
答案 6 :(得分: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;
}
}
}