Zasadniczo mam następujące pory:Jak mam wdrożyć Object.GetHashCode() dla złożonej równości?
class Foo {
public override bool Equals(object obj)
{
Foo d = obj as Foo ;
if (d == null)
return false;
return this.Equals(d);
}
#region IEquatable<Foo> Members
public bool Equals(Foo other)
{
if (this.Guid != String.Empty && this.Guid == other.Guid)
return true;
else if (this.Guid != String.Empty || other.Guid != String.Empty)
return false;
if (this.Title == other.Title &&
this.PublishDate == other.PublishDate &&
this.Description == other.Description)
return true;
return false;
}
}
Tak, problem jest taki: mam non-wymagane pole Guid
, który jest unikatowy identyfikator. Jeśli nie jest to ustawione, muszę spróbować określić równość w oparciu o mniej dokładne metryki jako próbę określenia, czy dwa obiekty są równe. Działa to dobrze, ale sprawia, że GetHashCode()
jest brudny ... Jak powinienem to zrobić? Naiwna implementacja byłaby podobna do:
public override int GetHashCode() {
if (this.Guid != String.Empty)
return this.Guid.GetHashCode();
int hash = 37;
hash = hash * 23 + this.Title.GetHashCode();
hash = hash * 23 + this.PublishDate.GetHashCode();
hash = hash * 23 + this.Description.GetHashCode();
return hash;
}
Ale jakie są szanse na zderzenie dwóch typów hasha? Oczywiście, nie oczekiwałbym, że będzie to 1 in 2 ** 32
. Czy to zły pomysł, a jeśli tak, to w jaki sposób powinienem to robić?
Ważniejsze jest to, że twój algorytm skrótu zgadza się z twoim algorytmem równości, niż rozkład jest jednolity. Pamiętaj, że celem skrótu jest uzyskanie czystej dystrybucji w tabeli mieszania; Dopóki nie jesteś masywnie wypaczony do jednego konkretnego kubła, szanse są dobre, nic ci nie będzie. Jeśli jesteś zaniepokojony, wybierz rozsądny scenariusz, który może spotkać konsumenta twojego obiektu - powiedzmy, umieszczając kilkaset z nich w słowniku, jeśli to rozsądne - i wykonaj kilka testów, aby sprawdzić, czy jesteś akceptowalny wyniki. –
Najbardziej kiedykolwiek widziałem w rzeczywistym użyciu było ~ 200, ale typowe użycie jest <30, więc prawdopodobnie masz rację. –
Heck, z mniej niż 30 pozycji, wyszukiwanie liniowe na liście połączonej jest prawdopodobnie wykonalne. Możesz zawsze zwracać kod skrótu, mieć 100% szansy na kolizję, a mimo to uzyskać akceptowalną wydajność. Istotą dobrej dystrybucji kodów skrótu jest uzyskanie skali wydajności, gdy rozmiar słownika staje się duży. Możesz mieć kiepską dystrybucję i nadal uzyskiwać dobre wyniki, jeśli zamierzasz umieścić tylko niewielką liczbę przedmiotów w tabeli. –