Is there a reason you should use ContainsKey over TryGetValue

I tried some tests, and it doesn't matter if everyone has hits or misses. TryGetValue is always faster. When should I use ContainsKey?

+4
source share
2 answers

It depends on what methods you use. If you open the Link Source , you will see.

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

As you can see, TryGetValuematches ContainsKey+ one array lookup.

If your logic is only to check for the presence of a key in Dictionaryand nothing related to that key (assuming a value for the key), you should use ContainsKey.

, TryGetValue ,

if(dic.ContainsKey(keyValue))
{
    dicValue = dic[keyValue]; // here you do more work!
}

Dictionary[key]

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

, 2 FindEntry + , ContainsKey dic[key]. FindEntry .

+13

. ContainsKey , . TryGetValue , . , , .

, string.Empty.

Dictionary<int,string> Dict = new Dictionary<int,string>();
string GetValue1(int key)
{
    string outValue;
    if (!Dict.TryGetValue(key, out outValue))
        outValue = string.Empty;
    return outValue;
}

string GetValue2(int key)
{
    return (Dict.ContainsKey(key))
        ? Dict[key]
        : string.Empty;
}

, (. ). , TryGetValue out, , . ​​ , , . , . , GetValue1 outValue, GetValue2 - .

BACON , GetValue2 2 , , . , , , , GetValue2 . , , , GetValue2. GetValue1.

ConcurrentDictionary, TryGetValue, , .

2 , (int vs string). , / .

[TestMethod]
public void TestString()
{
    int counter = 10000000;
    for (var x = 0; x < counter; x++)
        DictString.Add(x.ToString(), "hello");

    TimedLog("10,000,000 hits TryGet", () =>
    {
        for (var x = 0; x < counter; x++)
            Assert.IsFalse(string.IsNullOrEmpty(GetValue1String(x.ToString())));
    }, Console.WriteLine);

    TimedLog("10,000,000 hits ContainsKey", () =>
    {
        for (var x = 0; x < counter; x++)
            Assert.IsFalse(string.IsNullOrEmpty(GetValue2String(x.ToString())));
    }, Console.WriteLine);

    TimedLog("10,000,000 misses TryGet", () =>
    {
        for (var x = counter; x < counter*2; x++)
            Assert.IsTrue(string.IsNullOrEmpty(GetValue1String(x.ToString())));
    }, Console.WriteLine);

    TimedLog("10,000,000 misses ContainsKey", () =>
    {
        for (var x = counter; x < counter*2; x++)
            Assert.IsTrue(string.IsNullOrEmpty(GetValue2String(x.ToString())));
    }, Console.WriteLine);
}

[TestMethod]
public void TestInt()
{
    int counter = 10000000;
    for (var x = 0; x < counter; x++)
        DictInt.Add(x, "hello");

    TimedLog("10,000,000 hits TryGet", () =>
    {
        for (var x = 0; x < counter; x++)
            Assert.IsFalse(string.IsNullOrEmpty(GetValue1Int(x)));
    }, Console.WriteLine);

    TimedLog("10,000,000 hits ContainsKey", () =>
    {
        for (var x = 0; x < counter; x++)
            Assert.IsFalse(string.IsNullOrEmpty(GetValue2Int(x)));
    }, Console.WriteLine);

    TimedLog("10,000,000 misses TryGet", () =>
    {
        for (var x = counter; x < counter * 2; x++)
            Assert.IsTrue(string.IsNullOrEmpty(GetValue1Int(x)));
    }, Console.WriteLine);

    TimedLog("10,000,000 misses ContainsKey", () =>
    {
        for (var x = counter; x < counter * 2; x++)
            Assert.IsTrue(string.IsNullOrEmpty(GetValue2Int(x)));
    }, Console.WriteLine);
}

public static void TimedLog(string message, Action toPerform, Action<string> logger)
{
    var start = DateTime.Now;
    if (logger != null)
        logger.Invoke(string.Format("{0} Started at {1:G}", message, start));

    toPerform.Invoke();
    var end = DateTime.Now;
    var span = end - start;
    if (logger != null)
        logger.Invoke(string.Format("{0} Ended at {1} lasting {2:G}", message, end, span));
}

TestInt

10,000,000 hits TryGet Started at ...
10,000,000 hits TryGet Ended at ... lasting 0:00:00:00.3734136
10,000,000 hits ContainsKey Started at ...
10,000,000 hits ContainsKey Ended at ... lasting 0:00:00:00.4657632
10,000,000 misses TryGet Started at ...
10,000,000 misses TryGet Ended at ... lasting 0:00:00:00.2921058
10,000,000 misses ContainsKey Started at ...
10,000,000 misses ContainsKey Ended at ... lasting 0:00:00:00.2579766

ContainsKey 25% TryGetValue

TryGetValue 13% , ContainsKey

TestString

10,000,000 hits TryGet Started at ...
10,000,000 hits TryGet Ended at ... lasting 0:00:00:03.2232018
10,000,000 hits ContainsKey Started at ...
10,000,000 hits ContainsKey Ended at ... lasting 0:00:00:03.6417864
10,000,000 misses TryGet Started at ...
10,000,000 misses TryGet Ended at ... lasting 0:00:00:03.6508206
10,000,000 misses ContainsKey Started at ...
10,000,000 misses ContainsKey Ended at ... lasting 0:00:00:03.4912164

ContainsKey 13% TryGetValue

TryGetValue 4.6% , ContainsKey

+5

Source: https://habr.com/ru/post/1656880/


All Articles