想象一下代码:

public class obj
{
    // elided
}

public static Dictionary<string, obj> dict = new Dictionary<string, obj>();

方法1

public static obj FromDict1(string name)
{
    if (dict.ContainsKey(name))
    {
        return dict[name];
    }
    return null;
}

方法2

public static obj FromDict2(string name)
{
    try
    {
        return dict[name];
    }
    catch (KeyNotFoundException)
    {
        return null;
    }
}

我很好奇这两个函数的性能是否有差异,因为第一个函数应该比第二个函数慢——假设它需要两次检查字典是否包含值,而第二个函数只需要访问字典一次,但哇,实际上是相反的:

循环1 000 000个值(其中10 000个存在,90 000个不存在):

第一个函数:306毫秒 第二个函数:20483毫秒

为什么呢?

编辑:正如您可以在这个问题下面的评论中注意到的那样,在没有0个不存在的键的情况下,第二个函数的性能实际上比第一个函数略好。但一旦存在至少1个或多个不存在的密钥,第二个密钥的性能就会迅速下降。


一方面,抛出异常本身就很昂贵,因为堆栈必须被解开等等。 另一方面,通过键访问字典中的值的代价很低,因为这是一个快速的O(1)操作。

BTW:正确的方法是使用TryGetValue

obj item;
if(!dict.TryGetValue(name, out item))
    return null;
return item;

这样只访问字典一次而不是两次。 如果你真的想在键不存在时返回null,上面的代码可以进一步简化:

obj item;
dict.TryGetValue(name, out item);
return item;

这是可行的,因为如果不存在带name的键,TryGetValue将item设置为null。


Dictionaries are specifically designed to do super fast key lookups. They are implemented as hashtables and the more entries the faster they are relative to other methods. Using the exception engine is only supposed to be done when your method has failed to do what you designed it to do because it is a large set of object that give you a lot of functionality for handling errors. I built an entire library class once with everything surrounded by try catch blocks once and was appalled to see the debug output which contained a seperate line for every single one of over 600 exceptions!