使用一个对象作为通用的Dictionary键

如果我想使用对象作为Dictionary的关键字,我需要重写哪些方法才能以特定方式进行比较?

说我有一个有属性的类:

 class Foo { public string Name { get; set; } public int FooID { get; set; } // elided } 

我想创build一个:

 Dictionary<Foo, List<Stuff>> 

我希望具有相同FooID Foo对象被视为相同的组。 我需要在Foo类中重写哪些方法?

总结一下:我想将Stuff对象分类成Foo对象分组的列表。 Stuff对象将有一个FooID链接到他们的类别。

默认情况下,两个重要的方法是GetHashCode()Equals() 。 如果两个事物相等( Equals()返回true),它们具有相同的散列码是很重要的。 例如,你可能会“返回FooID” 作为GetHashCode()如果你想作为匹配。 你也可以实现IEquatable<Foo> ,但这是可选的:

 class Foo : IEquatable<Foo> { public string Name { get; set;} public int FooID {get; set;} public override int GetHashCode() { return FooID; } public override bool Equals(object obj) { return Equals(obj as Foo); } public bool Equals(Foo obj) { return obj != null && obj.FooID == this.FooID; } } 

最后,另一种select是提供一个IEqualityComparer<T>来做同样的事情。

正如你所希望的FooID是组的标识符,你应该使用它作为字典中的键而不是Foo对象:

 Dictionary<int, List<Stuff>> 

如果将Foo对象用作键,则只需实现GetHashCodeEquals方法即可仅考虑FooID属性。 对于Dictionary而言, Name属性只是无用的权重,所以您只需使用Foo作为int的包装。

因此,最好直接使用FooID值,然后不必实现任何东西,因为Dictionary已经支持使用int作为键。

编辑:
如果你想使用Foo类作为关键字, IEqualityComparer<Foo>很容易实现:

 public class FooEqualityComparer : IEqualityComparer<Foo> { public int GetHashCode(Foo foo) { return foo.FooID.GetHashCode(); } public bool Equals(Foo foo1, Foo foo2) { return foo1.FooID == foo2.FooID; } } 

用法:

 Dictionary<Foo, List<Stuff>> dict = new Dictionary<Foo, List<Stuff>>(new FooEqualityComparer()); 

对于Foo,您将需要重写object.GetHashCode()和object.Equals()

字典将调用GetHashCode()来计算每个值的哈希桶,等于比较两个Foo是否相同。

确保计算好的散列码(避免许多相同的Foo对象具有相同的散列码),但要确保两个等于Foos具有相同的散列码。 您可能需要从Equals-Method开始,然后(在GetHashCode())中使用您在Equals中比较的每个成员的哈希码。

 public class Foo { public string A; public string B; override bool Equals(object other) { var otherFoo = other as Foo; if (otherFoo == null) return false; return A==otherFoo.A && B ==otherFoo.B; } override int GetHashCode() { return 17 * A.GetHashCode() + B.GetHashCode(); } } 

什么关于Hashtable类!

 Hashtable oMyDic = new Hashtable(); Object oAnyKeyObject = null; Object oAnyValueObject = null; oMyDic.Add(oAnyKeyObject, oAnyValueObject); foreach (DictionaryEntry de in oMyDic) { // Do your job } 

在上面的方式,你可以使用任何对象(你的类对象)作为一个通用的字典键:)

我有同样的问题。 我现在可以使用任何我试过的对象作为关键字,因为重写了Equals和GetHashCode。

这是一个我用方法构build的类,在Equals(object obj)和GetHashCode()的覆盖内部使用。 我决定使用generics和哈希algorithm,应该能够覆盖大部分对象。 请让我知道,如果你在这里看到的东西不适用于某些types的对象,你有办法改善它。

 public class Equality<T> { public int GetHashCode(T classInstance) { List<FieldInfo> fields = GetFields(); unchecked { int hash = 17; foreach (FieldInfo field in fields) { hash = hash * 397 + field.GetValue(classInstance).GetHashCode(); } return hash; } } public bool Equals(T classInstance, object obj) { if (ReferenceEquals(null, obj)) { return false; } if (ReferenceEquals(this, obj)) { return true; } if (classInstance.GetType() != obj.GetType()) { return false; } return Equals(classInstance, (T)obj); } private bool Equals(T classInstance, T otherInstance) { List<FieldInfo> fields = GetFields(); foreach (var field in fields) { if (!field.GetValue(classInstance).Equals(field.GetValue(otherInstance))) { return false; } } return true; } private List<FieldInfo> GetFields() { Type myType = typeof(T); List<FieldInfo> fields = myType.GetTypeInfo().DeclaredFields.ToList(); return fields; } } 

这是如何在一个类中使用的:

 public override bool Equals(object obj) { return new Equality<ClassName>().Equals(this, obj); } public override int GetHashCode() { unchecked { return new Equality<ClassName>().GetHashCode(this); } }