2011-01-04 17 views
15

Korzystanie z tej klasyC# Hashset Zawiera nieunikalne Przedmioty

public class Foo 
{ 
    public string c1, c2; 

    public Foo(string one, string two) 
    { 
     c1 = one; 
     c2 = two; 
    } 

    public override int GetHashCode() 
    { 
     return (c1 + c2).GetHashCode(); 
    } 
} 

i ten HashSet

HashSet<Foo> aFoos = new HashSet<Foo>(); 
Foo aFoo = new Foo("a", "b"); 

aFoos.Add(aFoo); 
aFoos.Add(new Foo("a", "b")); 

label1.Text = aFoos.Count().ToString(); 

I uzyskać odpowiedź 2, kiedy na pewno powinno być 1. Czy istnieje sposób aby to naprawić więc mój HashSet zawiera tylko unikatowe obiekty?

Dzięki, Ash.

+6

Nie zastąpiłeś 'Równa się'. – Ani

Odpowiedz

25

Typ HashSet<T> ultamitely wykorzystuje równości celu ustalenia, czy 2 obiekty są równe, czy nie. W typie Foo masz tylko nadpisać GetHashCode, a nie równość. Oznacza to, że kontrole równości powrócą domyślnie do wersji Object.Equals, która używa równości odniesienia. To wyjaśnia, dlaczego widzisz wiele przedmiotów w HashSet<Foo>.

Aby to naprawić, należy zastąpić Equals w typie Foo.

public override bool Equals(object obj) { 
    var other = obj as Foo; 
    if (other == null) { 
    return false; 
    } 
    return c1 == other.c1 && c2 == other.c2; 
} 
+3

+1, ponieważ jest poprawny, ale można dodać, że skróty zwrócone przez 'GetHashCode' mogą kolidować dla różnych wartości, dlatego porównywanie kodu skrótu nie zapewnia równości obiektów w ogóle. – Lucero

7

Należy zastąpić metodę Equals. Tylko GetHashCode to za mało.

4

Należy również zastąpić metodę equals. Powodem tego jest to, że hashcode może kolidować dla dwóch obiektów, które nie są równe. W przeciwnym razie to nie zadziała.

public override bool Equals(Object obj) 
{ 
    Foo otherObject = obj as Foo; 
    return otherObject != null && otherObject.c1 == this.c1 && otherObject.c2 == this.c2; 
} 
+0

Wyrażenie "local.Equals (null)" powinno zwracać "false", a nie "true". – JaredPar

+0

To prawda, napisałem to szybko dla siebie :). –