我有一本字典:
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)
任何帮助表示赞赏!
答案 0 :(得分:2)
仅仅因为你覆盖了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撰写的this very good blog post&#34; GetHashCode指南和规则&#34;
答案 1 :(得分:1)
覆盖GetHasCode和Equal是在比较myClass的实例时。
以下是使用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 }
}
}
}