如果键不存在,C#Dictionary <int,int>查找会怎样?


121

我尝试检查null,但编译器警告说这种情况永远不会发生。我应该找什么?

Answers:


196

假设如果键确实存在,则要获取值,请使用Dictionary<TKey, TValue>.TryGetValue

int value;
if (dictionary.TryGetValue(key, out value))
{
    // Key was in dictionary; "value" contains corresponding value
} 
else 
{
    // Key wasn't in dictionary; "value" is now 0
}

ContainsKey然后使用索引器使它两次查找关键字,这是毫无意义的。)

请注意,即使你使用引用类型,为空检查是行不通的-索引的Dictionary<,>,如果你请求一个丢失的钥匙将抛出一个异常,而不是返回null。(Dictionary<,>和之间有很大的区别Hashtable。)


@JonSkeet TryGetValue是否也不进行双重查询(如本问题正文所述)?
nawfal 2012年

5
@nawfal:我看不出有任何问题表明这一点。它说它比要做更多的工作ContainsKey,这是正确的,因为它还必须提取值。但是,它没有进行两次查询。
乔恩·斯基特

天真的,我一直期望为null,但是对于Dictionary <TKey,enum>,这将返回枚举中的“ 0”等效项。
杰西2015年

23

如果字典KeyNotFound不包含您的密钥,则字典会引发异常。

如所建议的,ContainsKey是适当的预防措施。 TryGetValue也有效。

这使字典可以更有效地存储null值。如果没有这种行为,则检查[]运算符的结果是否为空将指示是否为空值或输入键不存在,这是不好的。


可以在MSDN上找到更多信息: msdn.microsoft.com/en-gb/library/9tee9ht2.aspx
Cyber​​zed

10

如果您只是在尝试添加新值之前进行检查,请使用以下ContainsKey方法:

if (!openWith.ContainsKey("ht"))
{
    openWith.Add("ht", "hypertrm.exe");
}

如果要检查值是否存在,请使用TryGetValueJon Skeet的答案中所述的方法。


8
TryGet更好
Ruben Bartelink 2010年

2
Coz,如果您立即在Contains之后获取,则您将通过哈希表解析键查找两次。Wintellect PowerCollections还具有一些GetValueElseAdd方法,您可以给它们提供一个值(或Func<TValue>),如果要添加的分辨率不存在,也可以将分辨率保存在“ Insert”上。我想没有将其放入.NET库的原因是因为如果在缓存
样式中

@rub:我想这取决于代码的目的。如果要使用该值,我同意那TryGetValue会更好,但是如果要检查字典是否包含该键以避免重复添加,我会说ContainsKey同样好(如果不是更好)。
FredrikMörk2010年

@Fredrik:如果你只是想要做一个遏制支票,那么,它的值得使用的containsKey。请注意,此答案的示例代码中并非如此。
乔恩·斯基特

@Jon:是的,我真的错过了添加值添加后立即获取的值。
FredrikMörk2010年

3

在尝试提取值之前,应检查Dictionary.ContainsKey(int key)。

Dictionary<int, int> myDictionary = new Dictionary<int, int>();
myDictionary.Add(2,4);
myDictionary.Add(3,5);

int keyToFind = 7;
if(myDictionary.ContainsKey(keyToFind))
{
    myValueLookup = myDictionay[keyToFind];
    // do work...
}
else
{
    // the key doesn't exist.
}

2
您为什么要使其进行两次查找?
乔恩·斯基特

2
@mookid:我认为不是。这个想法是尝试查找密钥,如果找到它,则采取一种行动,否则采取另一种行动,对吗?
乔恩·斯基特

3
@Jon-老实说?因为我不知道TryGetValue。值得庆幸的是,我现在要做,所以以后我会知道的。尽管'cos讨论很有价值,但我将保持这个答案不变。
ZombieSheep 2010年

@Jon Skeet-这就是为什么我在这里。:)
ZombieSheep 2010年

@JonSkeet因为在C#7之前,您不能TryGetValue在lambda表达式中使用。尽管这确实使我认为对C#的新扩展将是catch类似于null合并运算符的运算符。
NetMage

1

辅助类很方便:

public static class DictionaryHelper
{
    public static TVal Get<TKey, TVal>(this Dictionary<TKey, TVal> dictionary, TKey key, TVal defaultVal = default(TVal))
    {
        TVal val;
        if( dictionary.TryGetValue(key, out val) )
        {
            return val;
        }
        return defaultVal;
    }
}

有时我想知道为什么未将其添加到标准库中。如果没有条目,几乎所有使用哈希映射的语言都将返回null,而不是异常的异常。词典中不存在的项目不是异常行为。
亚当·赫斯

@AdamHess-这就是为什么您在C#中拥有Hashtable()的原因……不幸的是,您的密钥被装箱了... :(
veljkoz


0

您可能应该使用:

if(myDictionary.ContainsKey(someInt))
{
  // do something
}

您不能检查null的原因是这里的键是一个值类型。


1
值的类型无关紧要,因为检查null不会达到预期的效果。
乔恩·斯基特

@ Johannes,Jon的解决方案当然更好,但是询问者确实声明他检查了密钥是否存在,并且它是Dictionary <int,int>,因此密钥在这里也是值类型。
拉齐

0
int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;

如果字典中存在键,则它返回键的值,否则返回0。

希望这段代码对您有所帮助。


1
如果密钥存在,则此代码将查找两次。 TryGetValue足够了,请使用value代替result
Mathieu VIALES

0

考虑封装此特定字典的选项,并提供一种方法以返回该键的值:

public static class NumbersAdapter
{
    private static readonly Dictionary<string, string> Mapping = new Dictionary<string, string>
    {
        ["1"] = "One",
        ["2"] = "Two",
        ["3"] = "Three"
    };

    public static string GetValue(string key)
    {
        return Mapping.ContainsKey(key) ? Mapping[key] : key;
    }
}

然后,您可以管理此词典的行为。

例如此处:如果字典没有键,它将返回您通过参数传递的键。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.