[英]“the given key was not present in the dictionary” error when using a self-defined class as key
I've got code like this: 我有这样的代码:
if (CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key))
CounterForEachRelatedTagDict[tag.Key] += tag.Value;
Is it possible that the IF statement returns true, at the same time CounterForEachRelatedTagDict[tag.Key]
returns "the given key was not present in the dictionary" error? 是否有可能IF语句返回true,同时CounterForEachRelatedTagDict[tag.Key]
返回“给定的键不存在于字典中”错误? tag
is a KeyValuePair<MyClass,int>
. tag
是KeyValuePair<MyClass,int>
。
CounterForEachRelatedTagDict
is initiated like this: CounterForEachRelatedTagDict
的启动方式如下:
Dictionary<MyClass, int> CounterForEachRelatedTagDict = new Dictionary<MyType, int>();
MyClass
is like this MyClass
就是这样的
public class MyClass
{
public string name {get;set;}
public Guid Id { get; set; }
...
}
It seems almost unreasonable to me... 这似乎对我来说几乎是不合理的......
The problem is that your Equal
and GetHashCode
methods are out of sync for MyType
. 问题是您的Equal
和GetHashCode
方法与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. 当您使用CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key)
您正在使用Equals
对所有键执行线性搜索,以比较您要搜索的每个键的内容。
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. 当您在Dictionary
使用ContainsKey
,索引器或用于查找键的许多其他方法之一时,您首先使用GetHashCode
对键进行散列,然后它仅使用Equals
来查找哪个(希望极少数对象)在其中相同桶。
What's happening is that you have two object for which first.Equals(second)
returns true, but for which GetHashCode
returns two different values. 发生的事情是你有两个对象, first.Equals(second)
返回true,但GetHashCode
返回两个不同的值。 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
. 非常重要的是,当在Dictionary
使用对象作为键时, Equals
返回true
任何两个对象也必须为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. 请注意,这种查找键的方法虽然确实会强制您确保用作键的所有对象都具有合理的GetHashCode
实现(来自object
的默认实现很少合适),但这种算法非常高效(使用高效的哈希算法)这是值得的。 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
. 使用ContainsKey
或字典的索引器比通过每个键并比较它要快得多,这是您的Select
代码需要做的以避免使用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. 所以,回答你的问题,是的, CounterForEachRelatedTagDict.Select(x => x.Key).Contains(tag.Key)
很有可能找到一个项目而索引器不能。
First:You can use the ContainsKey
method instead of that Linq Query. 第一:您可以使用ContainsKey
方法而不是Linq Query。
Second: You must override the GetHashCode
and Equals
for MyType
. 第二:你必须重写GetHashCode
和Equals
为MyType
。 that's the way that Dictionary look up and compare the keys. 这就是Dictionary查找和比较键的方式。
Check out these similar questions: Dictionary.ContainsKey return False, but a want True , Using an object as a generic Dictionary key 看看这些类似的问题: Dictionary.ContainsKey返回False,但是想要True , 使用对象作为通用的Dictionary键
To use your type as a dictionary key you should override two methods: GetHashCode
and Equals
. 要将类型用作字典键,您应该重写两个方法: GetHashCode
和Equals
。
By default (if you'll not override GetHashCode
) every object of your type (even with the same field values) will return unique value. 默认情况下(如果您不会覆盖GetHashCode
)您的类型的每个对象(即使具有相同的字段值)将返回唯一值。 This means that you'll be able to find only exactly the same "reference" that you'll put into your dictionary. 这意味着您将只能找到与您的字典完全相同的“参考”。 Consider following two types: MyType1
that not overrides GetHashCode
and Equals
, and MyType2 that do: 考虑以下两种类型: MyType1
不是重写GetHashCode
和Equals
,并MyType2该做的事:
class MyType1
{
public MyType1(int id, string name) {Id = id; Name = name;}
public int Id {get; private set;}
public string Name {get; private set;}
}
internal class MyType2
{
public MyType2(int id, string name)
{
Id = id;
Name = name;
}
public int Id { get; private set; }
public string Name { get; private set; }
bool Equals(MyType2 other)
{
return Id == other.Id && string.Equals(Name, other.Name);
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != this.GetType()) return false;
return Equals((MyType2) obj);
}
public override int GetHashCode()
{
unchecked
{
return (Id*397) ^ Name.GetHashCode();
}
}
}
var d1 = new Dictionary<MyType1, int>();
d1[new MyType1(1, "1")] = 1;
d1[new MyType1(1, "1")]++; // will throw withKeyNotFoundException
var d2 = new Dictionary<MyType2, int>();
d1[new MyType2(1, "1")] = 1;
d1[new MyType2(1, "1")]++; // Ok, we'll find appropriate record in dictionary
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.