2009-09-27 13 views
14

Widzę inne zachowanie między używaniem .Equals i == między dwoma nowymi instancjami .NET 4.0 Tuple <>. Jeśli nadpisałem Equals na obiekcie w kodzie Tuple <> i wywołałem. Wygrane w Krotkach zostanie wywołane zastąpienie równych. Jeśli użyję == na Tuplach, nie zostanie wywołane zastąpienie równań. Czy jest to zgodne z projektem i ma sens?Czy to jest oczekiwane zachowanie równości w języku C# 4.0?

EDYCJA: Z odpowiedzi i komentarzy mogę powiedzieć, że nie jestem czysty. Wiem, że Tuple <> jest typem referencyjnym, a dla typów odniesienia == sprawdza tożsamość (ReferenceEquals). Ale czy powinien Tuple <> przesłonić ==, aby sprawdzić równość obiektów, które zawiera? Dla spójności prawdopodobnie nie.

Na przykład jeśli mam prosty obiekt

public class NameAndNumber 
{ 
    public int Number { get; set; } 
    public string Name { get; set; } 

    public override bool Equals(object obj) 
    { 
     if (obj is NameAndNumber) 
     { 
      NameAndNumber other = (NameAndNumber)obj; 
      return Number == other.Number && Name == other.Name; 
     } 

     return false; 
    } 
} 

a następnie zrobić coś takiego:

Tuple<NameAndNumber, NameAndNumber> left = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
Tuple<NameAndNumber, NameAndNumber> right = new Tuple<NameAndNumber, NameAndNumber>(
     new NameAndNumber { Name = "one", Number = 1 }, 
     new NameAndNumber { Name = "two", Number = 2 }); 
bool operatorResult = left == right; 
bool equalsResult = left.Equals(right); 
Console.Out.WriteLine("operatorResult = {0} equalsResult = {1}", 
     operatorResult, equalsResult); 

uzyskać operatorResult = false equalsResult = true

powinienem oczekiwać że?

Wiem, że implementacja równań na NameAndNumber nie jest "właściwa", to tylko uproszczony przykładowy kod.

Próbowałem również wdrażanie IEquatable, ==,! = I GetHashCode. Takie same wyniki.

+0

Dzięki za odpowiedzi i komentarze. Powinienem był się tego spodziewać. Zastępuję nasze projekty 3.5 Implementacja Tuple napisaliśmy sami z implementacją .NET 4. Nasz Tuple przejął ==, aby uzyskać zachowanie, którego oczekiwałem w pytaniu. Byłem zaskoczony, kiedy nie zachowywał się dokładnie tak, jak nasz niestandardowy. –

Odpowiedz

13

wyświetlane wyniki pochodzą z design compromise, Krotki są teraz dzielone między F # i C#. Najważniejsze jest to, że wszystkie krotki są rzeczywiście implementowane jako typy odniesienia, co nie było tak oczywiste.

Decyzja, czy Tuples powinna wykonywać głębokie lub płytkie kontrole równości została przeniesiona do dwóch interfejsów: IStructuralComparable, IStructuralEquatable. Zwróć uwagę, że te 2 są teraz również implementowane przez klasę Array.

6

Dla typu odniesienia: == wykonuje porównanie tożsamości, tzn. Zwraca wartość true tylko wtedy, gdy oba odwołania wskazują na ten sam obiekt. Oczekuje się, że metoda Equals() dokona porównania wartości, tzn. Zwróci wartość true, jeśli odwołania wskazują na obiekty, które są równoważne.

Dla typów referencyjnych gdzie == nie przeciążone, porównuje, czy dwie referencje odnoszą się do tego samego obiektu

+3

Z wyjątkiem sznurka, który jest magiczny. Sądzę, że szukam więcej magii. Czy spodziewałbyś się, że krotek typów wartości będzie sprawdzał wartość? Tak nie jest. –

+5

Nie ma magii - jest po prostu przeciążony == /! = Operatorzy; możesz to zobaczyć w reflektorze jako op_Equality i op_Inequality (na System.String). Tam ** jest **, jednak magia na takie rzeczy jak 'int' /' float' (zdefiniowane w specyfikacji) i 'Nullable ' (która używa operatorów "podniesionych"). –

+0

Nie jestem pewien, czy w pełni rozumiem twoje komentarze, twój Tuple w przykładowym kodzie jest typem referencyjnym, nie jest. –

1

domyślnie operatora == testy równości odniesienia, tak Tak wyniku, który oczekuje się widzenia.

Zobacz Guidelines for Overriding Equals() and Operator == (C# Programming Guide):

W języku C#, istnieją dwa rodzaje równości: równość odniesienia (również znany jako tożsamości) i równość wartość. Równość wartości jest ogólnie rozumiana w znaczeniu równości: oznacza, że ​​dwa obiekty zawierają te same wartości. Na przykład dwie liczby całkowite o wartości 2 mają wartość równą . Równość referencyjna oznacza , że nie ma dwóch obiektów, które można porównać z .

1

Domyślnie == (na klasie) oznacza równanie odniesienia; tj. czy są to te same przypadki; co powróci object.ReferenceEquals(x,y).

Możesz podać własne == /!= Operatorów, aby uzyskać oczekiwane zachowanie - a kiedy zastąpić Equals ważne jest, aby zastąpić GetHashCode zbyt (inaczej złamiesz wykorzystania jako kluczowy - Why is it important to override GetHashCode when Equals method is overriden in C#?):

public static bool operator == (NameAndNumber x, NameAndNumber y) { 
    if (x == null && y == null) return true; 
    if (x == null || y == null) return false; 
    return x.Number == y.Number && x.Name == y.Name; 
    // or if polymorphism is important: return x.Equals(y); 
} 
public static bool operator !=(NameAndNumber x, NameAndNumber y) { 
    return !(x == y); // lazy but works 
} 
public override int GetHashCode() { 
    return (Name == null ? 0 : Name.GetHashCode()) + 
     17 * Number.GetHashCode(); 
} 
+1

Wiem. Jak już wspomniałem, pokazałem uproszczoną implementację i zostawiłem GetHashCode na mniejszy przykład. Ale to nie zmieni tego, jak działa Tuple i nie mogę ich dodać do Tuple'a. Mogę czerpać z Tuple i dodawać je. –

+1

Jeśli problemem jest polimorfizm, to spraw, aby == używał '.Equals' - poza tym ... to po prostu działa' == '. Jeśli go nie przeładujesz, nie będzie działać w ten sposób! –

+0

@Marc Gravell. Myślę, że sedno problemu leży w tym, czy wbudowana klasa Tuple w .net 4.0 zachowuje się w ten czy inny sposób. Czy powinien zachowywać się jak standardowy typ referencyjny, czy delegować sprawdzanie równości do obiektów, które zawiera? To tylko pojemnik, więc powinniśmy się zatroszczyć o to, czy oba pojemniki są takie same, czy też powinniśmy sprawdzić zawartość pojemników. To nie jest moja implementacja programu Tuple, ale jest wbudowana w .net 4. Poprzednie biblioteki stron trzecich z implementacją Tuple lub Pair zastąpiłyby == sprawdzanie równości zawartych obiektów. –

Powiązane problemy