[英]Dictionary<>.ContainsKey gives RuntimeBinderException
[英]ContainsKey in dictionary of hashset<myClass>
我有一本字典:
Dictionary<HashSet<myClass>, List<MyObj>> myDict = ...
我有:
HashSet<myClass> myHashSet = ...
我想检查字典(myDict)是否包含myHashSet。
我试图覆盖两种方法:
1)平等
2)GetHashCode
public class myClass
{
public string id;
public int number;
public override bool Equals(object obj)
{
myClass other = obj as myClass;
bool ret = false;
if (other != null)
{
ret = (this.number == other.number) && (this.id == other.id);
}
return ret;
}
public override int GetHashCode()
{
return this.number ^ this.id.GetHashCode();
}
};
不幸的是,在字典中找到的键,代码返回false: myDict.ContainsKey(myHashSet)
任何帮助赞赏!
仅仅因为你覆盖了myClass
的Equals(
和GetHashCode()
并不意味着你覆盖了HashSet<myClass>
的Equals(
和GetHashCode()
,这就是你进行字典查找时所使用的内容。
如果您希望它工作,您需要将IEqualityComparer<HashSet<myClass>>
传递给字典的构造函数,以便在执行字典查找时使用该比较器。
public class myClassSetComperer : IEqualityComparer<HashSet<myClass>>
{
public bool Equals(HashSet<myClass> x, HashSet<myClass> y)
{
if (ReferenceEquals(x, y)) return true;
if (ReferenceEquals(null, x)) return false;
if (ReferenceEquals(null, y)) return false;
return x.SetEquals(y);
}
public int GetHashCode(HashSet<myClass> obj)
{
unchecked
{
int x = 0;
foreach (var myClass in obj)
{
x = (x*397) ^ myClass?.GetHashCode() ?? 0;
}
return x;
}
}
}
//elsewhere
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>, List<MyObj>>(new myClassSetComperer());
非常重要注意 :如果你做任何导致Equals(
或GetHashCode()
更改一次作为查找键的东西,字典键(和散列集)可怕地破坏。如果你修改了HashSet<myClass>
或其中一个myClass
对象之后你把它放在字典中,你将破坏字典和潜在的HashSet。请参阅Eric Lippert撰写的关于“GetHashCode指南和规则”的非常好的博客文章
在比较myClass的实例时,重写GetHasCode和Equal。
这是使用ContainsKey的示例,它通过对象引用进行检查。
Dictionary<HashSet<string>, List<string>> hashSetDictionary = new Dictionary<HashSet<string>, List<string>>();
var myHashSet = new HashSet<string>();
hashSetDictionary.Add(myHashSet, null);
Console.WriteLine(hashSetDictionary.ContainsKey(myHashSet));
这是您的代码的更新
public class myClass
{
public myClass(string text, int num)
{
this.Text = text;
this.Num = num;
}
public string Text { get; set; }
public int Num { get; set; }
}
public class MyObj { }
public class AlwaysTrueHashSet<T> : HashSet<T>
{
public override bool Equals(object obj)
{
return this.GetHashCode() == obj.GetHashCode();
}
public override int GetHashCode()
{
return "Counting hashcode".GetHashCode();
}
}
class Program
{
static void Main(string[] args)
{
Dictionary<HashSet<myClass>, List<MyObj>> myDict = new Dictionary<HashSet<myClass>,
List<MyObj>>();
var myHashSet1 = new AlwaysTrueHashSet<myClass>();
myHashSet1.Add(new myClass("123", 5));
myDict.Add(myHashSet1, null);
var myHashSet2 = new AlwaysTrueHashSet<myClass>();
myHashSet2.Add(new myClass("123", 5));
/*
* when containsKey is invoked, it's checking if the reference of myHashSet2 is the same as myHashSet1.
* That's the default behavior.
*
* extend HashSet, and override the gethashcode and equal methods
*/
if (myDict.ContainsKey(myHashSet2))
{
Console.WriteLine("in");
int i = 3; // it doesn't get this line }
}
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.