“the given key was not present in the dictionary” error when using a self-defined class as key

后端 未结 3 2001
没有蜡笔的小新
没有蜡笔的小新 2021-02-10 11:16

I\'ve got code like this:

if (CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key))
   CounterForEachRelatedTagDict[tag.Key] += tag.Value;
         


        
3条回答
  •  暖寄归人
    2021-02-10 12:03

    The problem is that your Equal and GetHashCode methods are out of sync for MyType.

    When you use CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key) you're performing a linear search through all of the keys using Equals to compare what you're searching for to each key.

    When you use ContainsKey in Dictionary, the indexer, or one of a number of other methods for finding a key you first hash the key using GetHashCode and then it only uses Equals to find which of the (hopefully very few objects) are identical within that bucket.

    What's happening is that you have two object for which first.Equals(second) returns true, but for which GetHashCode returns two different values. It's very important that, when using objects as keys in a Dictionary, any two objects for which Equals returns true must also return the same integer for GetHashCode. Ideally different objects should return different hash codes whenever possible, but it's not always possible (different objects with the same hash code are called "collisions").

    Note that this method of finding keys, while it does force you to ensure all objects used as keys have sensible implementations of GetHashCode (the default implementation that comes from object is rarely appropriate) this algorithm is * extraordinary* efficient (with efficient hashing algorithms) which is what makes it worthwhile. Using ContainsKey, or the indexer of the dictionary, is much, much faster than going through each key and comparing it, which is what your Select code needs to do to avoid using GetHashCode.

    So, to answer your question, yes, it's quite possible for CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key) to find an item while the indexer can't.

提交回复
热议问题