从MSDN的词条词典。TryGetValue方法:

This method combines the functionality of the ContainsKey method and the Item property. If the key is not found, then the value parameter gets the appropriate default value for the value type TValue; for example, 0 (zero) for integer types, false for Boolean types, and null for reference types. Use the TryGetValue method if your code frequently attempts to access keys that are not in the dictionary. Using this method is more efficient than catching the KeyNotFoundException thrown by the Item property. This method approaches an O(1) operation.

从描述中,不清楚它是否比调用ContainsKey然后进行查找更高效,还是更方便。TryGetValue的实现只是调用ContainsKey,然后Item,还是实际上比做单个查找更有效?

换句话说,哪个更有效(即哪个查找更少):

Dictionary<int,int> dict;
//...//
int ival;
if(dict.ContainsKey(ikey))
{
  ival = dict[ikey];
}
else
{
  ival = default(int);
}

or

Dictionary<int,int> dict;
//...//
int ival;
dict.TryGetValue(ikey, out ival);

注意:我不是在寻找一个基准!


当前回答

到目前为止,所有的答案虽然不错,但都忽略了一个关键问题。

API类中的方法(例如。net框架)构成了接口定义的一部分(不是c#或VB接口,而是计算机科学意义上的接口)。

因此,询问调用这样的方法是否更快通常是不正确的,除非速度是正式接口定义的一部分(在本例中并非如此)。

传统上,无论语言、基础设施、操作系统、平台或机器架构如何,这种快捷方式(结合搜索和检索)都更高效。它也更具有可读性,因为它明确地表达了您的意图,而不是暗示它(从代码的结构中)。

所以答案(来自一个灰色的老黑客)肯定是“是的”(TryGetValue比ContainsKey和Item [Get]的组合更可取,以从字典中检索值)。

如果您认为这听起来很奇怪,可以这样想:即使TryGetValue、ContainsKey和Item [Get]的当前实现没有产生任何速度差异,您可以假设未来的实现(例如。net v5)可能会做到(TryGetValue会更快)。考虑软件的生命周期。

顺便说一句,有趣的是,典型的现代接口定义技术仍然很少提供正式定义时间约束的任何方法。也许是。net v5?

其他回答

谁在乎呢? -)

您可能会问这个问题,因为TryGetValue使用起来很麻烦——所以用扩展方法像这样封装它。

public static class CollectionUtils
{
    // my original method
    // public static V GetValueOrDefault<K, V>(this Dictionary<K, V> dic, K key)
    // {
    //    V ret;
    //    bool found = dic.TryGetValue(key, out ret);
    //    if (found)
    //    {
    //        return ret;
    //    }
    //    return default(V);
    // }


    // EDIT: one of many possible improved versions
    public static TValue GetValueOrDefault<K, V>(this IDictionary<K, V> dictionary, K key)
    {
        // initialized to default value (such as 0 or null depending upon type of TValue)
        TValue value;  

        // attempt to get the value of the key from the dictionary
        dictionary.TryGetValue(key, out value);
        return value;
    }

然后只需呼叫:

dict.GetValueOrDefault("keyname")

or

(dict.GetValueOrDefault("keyname") ?? fallbackValue) 

一个快速的基准测试显示TryGetValue略有优势:

    static void Main() {
        var d = new Dictionary<string, string> {{"a", "b"}};
        var start = DateTime.Now;
        for (int i = 0; i != 10000000; i++) {
            string x;
            if (!d.TryGetValue("a", out x)) throw new ApplicationException("Oops");
            if (d.TryGetValue("b", out x)) throw new ApplicationException("Oops");
        }
        Console.WriteLine(DateTime.Now-start);
        start = DateTime.Now;
        for (int i = 0; i != 10000000; i++) {
            string x;
            if (d.ContainsKey("a")) {
                x = d["a"];
            } else {
                x = default(string);
            }
            if (d.ContainsKey("b")) {
                x = d["b"];
            } else {
                x = default(string);
            }
        }
   }

这个生产

00:00:00.7600000
00:00:01.0610000

使ContainsKey + Item访问速度慢了40%,假设命中和错过的混合均匀。

此外,当我将程序更改为总是错过(即总是查找“b”)时,两个版本变得同样快:

00:00:00.2850000
00:00:00.2720000

然而,当我让它“all hits”时,TryGetValue仍然是一个明显的赢家:

00:00:00.4930000
00:00:00.8110000

TryGetValue会更快。

ContainsKey使用与TryGetValue相同的检查,后者在内部引用实际的条目位置。Item属性实际上具有与TryGetValue几乎相同的代码功能,除了它将抛出异常而不是返回false。

在Item后面使用ContainsKey基本上重复了查找功能,这在本例中是计算的主要部分。

到目前为止,所有的答案虽然不错,但都忽略了一个关键问题。

API类中的方法(例如。net框架)构成了接口定义的一部分(不是c#或VB接口,而是计算机科学意义上的接口)。

因此,询问调用这样的方法是否更快通常是不正确的,除非速度是正式接口定义的一部分(在本例中并非如此)。

传统上,无论语言、基础设施、操作系统、平台或机器架构如何,这种快捷方式(结合搜索和检索)都更高效。它也更具有可读性,因为它明确地表达了您的意图,而不是暗示它(从代码的结构中)。

所以答案(来自一个灰色的老黑客)肯定是“是的”(TryGetValue比ContainsKey和Item [Get]的组合更可取,以从字典中检索值)。

如果您认为这听起来很奇怪,可以这样想:即使TryGetValue、ContainsKey和Item [Get]的当前实现没有产生任何速度差异,您可以假设未来的实现(例如。net v5)可能会做到(TryGetValue会更快)。考虑软件的生命周期。

顺便说一句,有趣的是,典型的现代接口定义技术仍然很少提供正式定义时间约束的任何方法。也许是。net v5?

由于到目前为止没有一个答案真正回答了这个问题,下面是我在一些研究后找到的一个可以接受的答案:

如果你反编译TryGetValue,你会看到它是这样做的:

public bool TryGetValue(TKey key, out TValue value)
{
  int index = this.FindEntry(key);
  if (index >= 0)
  {
    value = this.entries[index].value;
    return true;
  }
  value = default(TValue);
  return false;
}

而ContainsKey方法是:

public bool ContainsKey(TKey key)
{
  return (this.FindEntry(key) >= 0);
}

所以TryGetValue只是ContainsKey加上数组查找,如果项目是存在的。

似乎TryGetValue的速度几乎是ContainsKey+Item组合的两倍。