C# ContainsKey与TryGetValue方法探究

最近在进行在做一个链路选择的需求,涉及到字典存储。发现C#的Dictionary提供了ContainsKey和TryGetValue两个方法,都可以来判断字典中是否存在对应的Key值。那么这两个方法有什么区别呢?我们在编写代码的过程中如何选取呢?

我先创建了一个Dictionary<string, int>的字典,然后从0递增到一千万分别给这个字典添加了数据。

static Dictionary<string, int> dic = new Dictionary<string, int>();
const int TOTALNUM = 10000000;

for (int i = 0; i < TOTALNUM; i++)
{
    dic.Add(i.ToString(), i);
}

我们借助StopWatch,对ContainsKey和TryGetValue分别进行一千万次的查找,比较两者所花费的时间。

Stopwatch stopwatch1 = new Stopwatch(); // TryGetValue
Stopwatch stopwatch2 = new Stopwatch(); // COntainsKey

测试环境:

  • IDE工具:VS2019
  • CPU:i7-8700
  1. 当取出的Value在执行过程中有被使用时:

    stopwatch1.Start();
    long a = 0;
    for (int i = 0; i < TOTALNUM; i++)
    {
        string str = i.ToString();
        if (dic.TryGetValue(str, out var value))
        {
            // Value被使用
            a = a + value;
        }
    }
    stopwatch1.Stop();
    
    stopwatch2.Start();
    long b = 0;
    for (int i = 0; i < TOTALNUM; i++)
    {
        string str = i.ToString();
        if (dic.ContainsKey(str))
        {
            // Value被使用
            b = b + dic[str];
        }
    }
    stopwatch2.Stop();
    

    C# ContainsKey与TryGetValue方法探究

    ContainsKey所花费的时间较多

  2. 当没有对字典所对应Key的Value进行操作时:

    ...
        if (dic.TryGetValue(str, out var value))
        {
            a = a + 1;
        }
    ...
    
    ...
        if (dic.ContainsKey(str))
        {
            b = b + 1;
        }
    ...
    

    C# ContainsKey与TryGetValue方法探究

    TryGetValue花费的时间更多

  3. 查看源码:

    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;
    }
    
    public bool ContainsKey(TKey key)
    {
        return (this.FindEntry(key) >= 0);
    }
    
    
    public TValue this[TKey key] 
    {
    	get 
        {
        	int i = FindEntry(key);
            if (i >= 0) return entries[i].value;
            ThrowHelper.ThrowKeyNotFoundException();
            return default(TValue);
        }
        set 
        {
        	Insert(key, value, false);
        }
    }
    

    查看源码我们发现TryGetValue是在ContainsKey的基础上直接从存储中取出Value。有一个很关键的函数FindEntry我们在三个函数都有看到,说明我们如果在使用完ContainsKey在用Dic[Key]去取值的时候,会多一次开销。

总结

  • 在数据量不大的情况下,两者并没有太大的差别。在数据量大的情况下,如果对Value并没有操作推荐用ContainsKey,反之则使用TryGetValue。当Key的命中率远低于50%,且操作Value时,也可以考虑使用ContainsKey。

C# ContainsKey与TryGetValue方法探究

C# ContainsKey与TryGetValue方法探究

上一篇:C#三种方法调用WebService接口


下一篇:PHP消息队列处理框架php-resque