Using the field of an object as a generic Dictionary key
如果我想使用对象作为
说我有一个具有属性的类:
1 2 3 4 5 6 | class Foo { public string Name { get; set; } public int FooID { get; set; } // elided } |
我想创建一个:
1 | Dictionary<Foo, List<Stuff>> |
我希望具有相同
总结一下:我想将
默认情况下,两个重要方法是
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | 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; } } |
最后,另一种选择是提供
当您希望
1 | Dictionary<int, List<Stuff>> |
如果将
因此,最好直接使用
编辑:
如果仍然要使用
1 2 3 4 | 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; } } |
用法:
1 | 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中比较的每个成员的哈希码进行xor处理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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(); } } |
我有同样的问题。由于覆盖了Equals和GetHashCode,我现在可以将尝试使用的任何对象用作键。
这是我使用方法构建的类,该方法可在Equals(object obj)和GetHashCode()的重写内部使用。我决定使用泛型和哈希算法,该算法应该能够覆盖大多数对象。如果您在此处发现不适用于某些类型的对象的任何东西,并且有改进的方法,请告诉我。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | 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; } } |
这是在类中的用法:
1 2 3 4 5 6 7 8 9 10 11 12 | public override bool Equals(object obj) { return new Equality<ClassName>().Equals(this, obj); } public override int GetHashCode() { unchecked { return new Equality<ClassName>().GetHashCode(this); } } |
那
1 2 3 4 5 6 7 8 | Hashtable oMyDic = new Hashtable(); Object oAnyKeyObject = null; Object oAnyValueObject = null; oMyDic.Add(oAnyKeyObject, oAnyValueObject); foreach (DictionaryEntry de in oMyDic) { // Do your job } |
通过以上方法,您可以将任何对象(您的类对象)用作通用的Dictionary键:)