C# 哪种机制是扩展字典以处理丢失键的更好方法?为什么?
我发现自己有很多小麻烦-我有一本C# 哪种机制是扩展字典以处理丢失键的更好方法?为什么?,c#,dictionary,extension-methods,keynotfoundexception,C#,Dictionary,Extension Methods,Keynotfoundexception,我发现自己有很多小麻烦-我有一本字典,其中包含可能存在或不存在的值 所以正常的行为是使用索引器,如下所示: object result = myDictionary["key"]; 但是,如果字典中没有“key”,则会抛出KeyNotFoundException,因此您可以这样做: object val; if (!myDictionary.TryGetValue("key", out val)) { val = ifNotFound; } 这很好,除了我可以一行有一堆这些-Tr
字典
,其中包含可能存在或不存在的值
所以正常的行为是使用索引器,如下所示:
object result = myDictionary["key"];
但是,如果字典中没有“key”
,则会抛出KeyNotFoundException
,因此您可以这样做:
object val;
if (!myDictionary.TryGetValue("key", out val))
{
val = ifNotFound;
}
这很好,除了我可以一行有一堆这些-TryGetValue
开始感觉非常笨拙
因此,选项1是一种扩展方法:
public static TValue TryGet<TKey, TValue>(
this Dictionary<TKey, TValue> input,
TKey key,
TValue ifNotFound = default(TValue))
{
TValue val;
if (input.TryGetValue(key, out val))
{
return val;
}
return ifNotFound;
}
这很简单,但是使用一个与现有实例方法名称相似的附加扩展方法可能会增加混乱并降低可维护性。它也与字典的索引器集不一致——该索引器集将处理丢失的键
因此,选项2是IDictionary
的一个新实现,它使用Dictionary
的隐式强制转换,但它是一个返回default(TValue)
的索引器,而不是抛出KeyNotFoundException
让我这样做:
ForgivingDictionary<string, object> dict = myDictionary;
object val = dict["key"] ?? ifNotFound;
// do stuff to val, then...
dict["key"] = val;
宽恕字典dict=myDictionary;
object val=dict[“key”]??如果没有发现;
//对瓦尔做点什么,然后。。。
dict[“key”]=val;
因此,现在get和set值是一致的,但是值类型更混乱,creditingdictionary
涉及更多的代码
这两种方法看起来都很“混乱”——在.Net中已经有更好的方法了吗
两种方法都做出了可能导致混淆的妥协,但其中一种方法比另一种更明显/清晰吗?为什么 我无法从您的问题中推断出当找不到密钥时应该做什么。我可以想象在这种情况下什么都不应该做,但我也可以想象相反的情况。 无论如何,对于您所描述的一系列TryGetValue语句,一个优雅的替代方法是使用以下扩展方法之一。我提供了两个选项,这取决于字典不包含键时是否应该执行某些操作:
/// <summary> Iterates over all values corresponding to the specified keys,
///for which the key is found in the dictionary. </summary>
public static IEnumerable<TValue> TryGetValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, IEnumerable<TKey> keys)
{
TValue value;
foreach (TKey key in keys)
if (dictionary.TryGetValue(key, out value))
yield return value;
}
/// <summary> Iterates over all values corresponding to the specified keys,
///for which the key is found in the dictionary. A function can be specified to handle not finding a key. </summary>
public static IEnumerable<TValue> TryGetValues<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, IEnumerable<TKey> keys, Action<TKey> notFoundHandler)
{
TValue value;
foreach (TKey key in keys)
if (dictionary.TryGetValue(key, out value))
yield return value;
else
notFoundHandler(key);
}
当命名要替换现有方法的扩展方法时,我倾向于在方法名称中添加特殊性,而不是缩短它:
GetValueOrDefault(...)
对于宽恕字典
,您可以约束TKey
,使其不能是值类型。但是,如果您必须处理其中的值类型,您将为值类型返回一些内容,最好的选择是返回default(TKey)
,因为您不能返回null
老实说,我会选择扩展方法
Edit:GetValueOrDefault()
,当然,如果没有找到键,它不会添加到字典中。如果找不到,我只会返回一个默认值,因为它就是这样命名的。如果希望它也能插入,一个好名字应该是GetValueOrInsertDefault()
或者
public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> input,
TKey key)
{
return input.ContainsKey(key) ? input[key] : *some default value*;
}
公共静态TValue TryGet(此字典输入,
TKey(钥匙)
{
返回input.ContainsKey(key)?input[key]:*一些默认值*;
}
好吧,据我所知,您需要的只是扩展方法的更好名称,可能更具体-例如SafeGetValue、GetOrUseValue等。扩展方法即使在框架类中也很常见,所以我想你不应该对它们感到惊讶。我认为扩展方法不会引起混乱,并且具有适用于所有词典的巨大优势。myDictionary.TryGet(“key1”)??如果没有发现代码>语法只适用于引用对象,对吗?当然,如果您的字典值是int、double、decimals等,默认值(TValue)将返回0,您将无法区分与键关联的合法0和由于键不存在而返回的默认0。使用bool ContainsKey(字符串键)
method.IMHO时,应该将“Try”前缀专门用于至少接收一个out参数并返回bool的方法,以避免混淆。如果找不到键,则返回default(TValue)
,对于引用类型,它将是null
,对于值类型,它将是默认值(0
对于int
等等)。我不确定您的TryGetValues
方法是否满足我的需要-我认为在这种情况下,我可能会使用Linqjoin
来代替。我也会使用扩展方法,并使用相同的名称。有了intellisense和autocomplete,像这样稍长一点的名字很难让人注意到。:)一个方法的名称应该是清晰的,并且可以帮助识别它的功能,而不需要查找它。公平的说,似乎大家的共识是扩展方法最好,但是使用一个更具描述性的名称。但是扩展方法并没有添加到字典中,它只是包装了TryGetValue
@Keith:是的,这是不对的。我重新措辞了。最近我自己也做了类似的事情,增加了这一点,使填充字典变得更容易(特别是,Dictionary
-风格的填充)。这需要两个显式查找,而OP的方法只需要一个,所以IMHO不是最佳的。@Mikey Cee正确地定义了Dictionary.TryGetValue(key,out val)
比字典快。包含密钥吗?输入[键]:默认值
。我的方法还使用了一个可选值,或者在找不到键时使用一个可选值。
GetValueOrDefault(...)
public static TValue TryGet<TKey, TValue>(this Dictionary<TKey, TValue> input,
TKey key)
{
return input.ContainsKey(key) ? input[key] : *some default value*;
}