【问题标题】:What happens to C# Dictionary<int, int> lookup if the key does not exist?如果键不存在,C# Dictionary<int, int> 查找会发生什么?
【发布时间】:2011-01-09 11:40:16
【问题描述】:

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

【问题讨论】:

    标签: c# dictionary


    【解决方案1】:

    假设您想在键确实存在的情况下获取值,请使用Dictionary&lt;TKey, TValue&gt;.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,然后索引器使其向上查找键两次,这是毫无意义的。)

    请注意,即使您使用引用类型,也无法检查 null - 如果您请求缺少的键,Dictionary&lt;,&gt; 的索引器将抛出异常,而不是返回 null。 (这是Dictionary&lt;,&gt;Hashtable 之间的一个很大区别。)

    【讨论】:

    • @JonSkeet TryGetValue 不是也在做双重查找吗(as stated in this question body)?
    • @nawfal:我没有看到任何迹象表明该问题表明了这一点。它说它比ContainsKey 做了更多的工作,这是真的,因为它也必须提取价值。但它并没有进行两次查找。
    • 天真地,我一直期待 null,但对于 Dictionary,这将返回枚举中的“0”等价物。
    【解决方案2】:

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

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

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

    【讨论】:

    【解决方案3】:

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

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

    如果您要检查该值是否存在,请使用 Jon Skeet 的回答中所述的 TryGetValue 方法。

    【讨论】:

    • 因为如果您在包含后立即获取,您将通过哈希表解析密钥查找两次。 Wintellect PowerCollections 还具有GetValueElseAdd 方法,如果您要在不存在的情况下添加,则您可以给这些方法一个值(或Func&lt;TValue&gt;)来保存插入上的分辨率。我想没有进入.NET库的原因是因为如果您在缓存样式中使用它,则添加路径的频率较低]
    • @rub:我想这取决于代码的用途。如果您想使用该值,我同意TryGetValue 会更好,但是如果您想检查字典是否包含键以避免重复添加,我会说ContainsKey 一样好(如果不是更好)。
    • @Fredrik:如果您想要进行遏制检查,那么是的,值得使用 ContainsKey。请注意,此答案的示例代码中并非如此。
    • @Jon: 是的,我实际上错过了添加后立即获取的附加值。
    • @Mork:你说得对,我同意。我评论的原因是该帖子没有明确说明您通常想要执行 ContainsKey(仅)或 TryGet(包含 + Get)或 TryGet / Add(在帖子中的代码示例中没有另一个 Get)
    【解决方案4】:

    在尝试提取值之前,您应该检查 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.
    }
    

    【讨论】:

    • 为什么要让它进行两次查找?
    • @mookid:在我看来不是。我们的想法是尝试查找密钥,如果找到则采取一种行动,否则采取另一种行动,对吗?
    • @Jon - 老实说?因为我不知道TryGetValue。谢天谢地,我现在这样做了,所以我以后会知道的。我将保持这个答案不变,尽管 'cos 讨论很有价值。
    • @JonSkeet 因为在 C# 7 之前,您不能在 lambda 表达式中使用 TryGetValue。虽然这确实让我认为 C# 的新扩展将是类似于 null 合并运算符的 catch 运算符。
    • @NetMage:你可以在 lambda 表达式中做到这一点 - 只是不是一个表达式主体的 lambda 表达式。
    【解决方案5】:

    辅助类很方便:

    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;
        }
    }
    

    【讨论】:

    • 有时我想知道为什么没有将它添加到标准库中。如果没有条目,几乎所有使用 hashmap 的语言都会返回 null,而不是异常。字典中不存在的项目不是异常行为。
    • @AdamHess - 这就是为什么你在 c# 中有 Hashtable() ......不幸的是,你的钥匙被装箱了...... :(
    【解决方案6】:

    ContainsKey 是你要找的。​​p>

    【讨论】:

      【解决方案7】:

      您可能应该使用:

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

      不能检查null的原因是这里的key是值类型。

      【讨论】:

      • 值的类型有点无关紧要,因为检查 null 不会有预期的效果。
      • @Johannes,Jon 的解决方案当然要好很多,但是提问者确实说他检查了 key 是否存在,并且是 Dictionary,所以 key 也是 value在这里输入。
      【解决方案8】:

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

      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;
          }
      }
      

      然后你可以管理这个字典的行为。

      例如这里:如果字典没有键,则返回您通过参数传递的键。

      【讨论】:

        【解决方案9】:
        int result= YourDictionaryName.TryGetValue(key, out int value) ? YourDictionaryName[key] : 0;
        

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

        希望这段代码能帮到你。

        【讨论】:

        • 如果key存在,这段代码会查找两次。 TryGetValue 就够了,用value 代替result
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-08-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多