[英]Overriding GetHashCode with different properties
我有這個對象:
public class Foo {
public string MyOwnId { get; set; }
public Guid FooGuid { get; } = Guid.NewGuid();
}
我希望Equals()
只關心那些有MyOwnId
,否則他們永遠不會平等。 當Foo
有一個MyOwnId
我嘗試使用它,否則我想使用FooGuid
。
由於FooGuid
可能永遠不會是相同的,我做了類似這樣的事情:
public bool Equals(Foo foo) {
if (foo== null) return false;
return MyOwnId.Equals(foo.MyOwnId);
}
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((Foo)obj);
}
public override int GetHashCode() {
int hash = 13;
hash = (hash*7) + (!string.IsNullOrEmpty(MyOwnId) ? MyOwnId.GetHashCode() : FooGuid.GetHashCode());
return hash;
}
這是做我想要的正確方法嗎? 或者我還需要更改我的Equals
方法,以便它看起來像我的GetHashCode
? 例如:
public bool Equals(Foo foo) {
if (foo == null) return false;
if (string.IsNullOrEmpty(MyOwnId) || string.IsNullOrEmpty(foo.MyOwnId)) return false;
return MyOwnId.Equals(foo.MyOwnId);
}
好吧,走着瞧。 您對Equals
和GetHashCode
是錯誤的 。
Equals
和GetHashCode
不能拋出異常; 反例是
Foo A = new Foo();
Foo B = new Foo() {
MyOwnId = "bla-bla-bla",
};
// Throws an exception
if (A.Equals(B)) {}
如果兩個實例通過Equals
相等,則這些實例必須具有相同的哈希碼; 反例是
Foo A = new Foo() {
MyOwnId = "",
};
Foo B = new Foo() {
MyOwnId = "",
};
if (A.Equals(B)) {
// Hashcodes must be equal and they are not
Console.Write(String.Format("{0} != {1}", A.GetHashCode(), B.GetHashCode()));
}
可能(最簡單)的實現
// since you've declared Equals(Foo other) let others know via interface implementation
public class Foo: IEquatable<Foo> {
public string MyOwnId { get; set; }
public Guid FooGuid { get; } = Guid.NewGuid();
public bool Equals(Foo other) {
if (Object.ReferenceEquals(this, other))
return true;
else if (Object.ReferenceEquals(null, other))
return false;
else
return String.Equals(MyOwnId, other.MyOwnId);
}
public override bool Equals(object obj) {
return Equals(obj as Foo); // do not repeat youself: you've got Equals already
}
public override int GetHashCode() {
// String.GetHashCode is good enough, do not re-invent a wheel
return null == MyOwnId ? 0 : MyOwnId.GetHashCode();
}
}
或者我還需要更改我的Equals方法,以便它看起來像我的GetHashCode一樣?
您可以更改Equals
以匹配要求解決相等的方式。 你做到了這一點。
您將GetHashCode()
更改為鍵入相同的信息。 在這種情況下:
public override int GetHashCode()
{
return MyOwnId == null ? 0 : MyOwnId.GetHashCode();
}
順便說一句,你的Equals(object)
有點過於復雜。 我會用:
public override bool Equals(object obj)
{
return Equals(obj as Foo);
}
這會將obj
為null的情況傳遞給特定的Equals()
(它也必須處理它),通過將Equals()
傳遞給null(無論如何都是false)來處理obj
是不是Foo
的東西並傳遞處理obj
的情況是從Foo
派生的東西也更具體(再次,必須處理)。
在快捷方式ReferenceEquals
只有一個字段進行比較,還有,它的比較將具有相同的不值得在這里做ReferenceEquals
快捷。 你不會在專門的Foo
處理foo
是派生類型。 如果Foo
沒有密封,你應該包括:
public bool Equals(Foo foo)
{
return (object)foo != null &&
foo.GetType() == GetType() &&
MyOwnId.Equals(foo.MyOwnId);
}
如果Foo
被密封,那么應該省略GetType()
比較。
如果Equals()
的邏輯比這更復雜,那么喜歡:
public bool Equals(Foo foo)
{
if ((object)foo == (object)this)
return true;
return (object)foo != null &&
foo.GetType() == GetType() &&
// Some more complicated logic here.
}
確實是有益的,但它應該是在特定的過載而不是一般的覆蓋。
(在==
重載時,執行引用相等性檢查更有利,因為它們必須考慮兩個操作數都為null的可能性,因此它們也可能認為它們都是相同的,隱含地包含該情況)。
哈希函數必須具有以下屬性:
請參閱https://msdn.microsoft.com/en-us/library/system.object.gethashcode(v=vs.110).aspx
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.