2010-09-16 7 views
5

Uderzyło mnie dziwne "asymetria" w języku C#, którego tak naprawdę nie rozumiem. Zobacz poniższy kod:Object.Equals jest wirtualny, ale Object.operator == nie używa go w języku C#?

using System; 
using System.Diagnostics; 
namespace EqualsExperiment 
{ 
    class Program 
    { 
     static void Main(string[] args) 
     { 
      object apple = "apple"; 
      object orange = string.Format("{0}{1}", "ap", "ple"); 
      Console.WriteLine("1"); 
      Debug.Assert(apple.Equals(orange)); 
      Console.WriteLine("2"); 
      Debug.Assert(apple == orange); 
      Console.WriteLine("3"); 
     } 
    } 
} 

Dla wszystkich guru .NET może być oczywiste, ale drugie potwierdzenie nie powiedzie się.

W języku Java dowiedziałem się, że == jest synonimem czegoś o nazwie Object.ReferenceEquals. W języku C#, myślałem, że Object.operator == używa Object.Equals, który jest wirtualny, więc jest overriden w klasie System.String.

Czy ktoś może wyjaśnić, dlaczego drugie stwierdzenie kończy się niepowodzeniem w C#? Które z moich założeń są złe?

+0

Znalazłem odpowiedź (http://stackoverflow.com/questions/1766492/c-overloading-operator-versus-equals/1849288#1849288) na moje pytanie również w innym wątku. Wydaje się, że 'object.operator ==' używa 'object.ReferenceEquals', ale' string.operator == 'używa' object.Equals'. Jest to dla mnie intuicyjne, ponieważ 'object.Equals' jest wirtualne, więc może być już użyte w' object.operator == '. – wigy

Odpowiedz

7

Operator == nie jest synonimem, jest operatorem zdefiniowanym dla różnych typów.

Operator == jest zdefiniowany dla ciągów, a następnie ma faktycznie użyć metody Equals:

public static bool operator ==(string a, string b) { 
    return Equals(a, b); 
} 

Jednak w kodzie nie są za pomocą operatora na sznurkach, używasz go na obiektach, więc otrzymujesz operator == zdefiniowany dla obiektów, który używa ReferenceEquals do porównania.

Które przeciążenie operatora do użycia jest określane w czasie kompilacji, więc jest to typ zmiennych, które decydują o przeciążeniu, a nie rzeczywisty typ obiektów, do których odnoszą się zmienne.

+0

Hmmm. Tak więc mówisz, że Object.operator == jest zdefiniowany w ReferenceEquals, natomiast String.operator == jest zdefiniowany jako Equals. Czy to nie jest miłe i intuicyjne? – wigy

+1

@wigu: W większości przypadków działa bardzo dobrze, ale są oczywiście sytuacje, takie jak twój przykład, gdzie możesz się spodziewać porównania, które zostanie określone w czasie wykonywania. Z pewnością jest bardziej intuicyjny niż na przykład w C++ i Javie, gdzie nie można w niezawodny sposób używać operatora == na ciągach. W VB operator = określa porównanie w czasie wykonywania, co jest bardziej zgodne z działaniem VB, ale daje kilka innych sytuacji, w których może cię zaskoczyć. W języku C# możliwe jest określenie z kodu dokładnie, jakie porównanie będzie używane, co jest bardziej zgodne z ogólnym działaniem C#. – Guffa

+0

Dzięki Guffa. Wiem, że to lepsze niż C, Java czy VB. Operatory C++ mogą być wirtualne, więc masz tam różne problemy.Właśnie dlatego większość standardów kodowania w C++ używa warunków Yoda takich jak 'if (5 == coś) {...}' Z twojej odpowiedzi zrozumiałem, że projektanci szkieletu myśleli, że ReferenceEquals jest bardziej intuicyjny dla niektórych programistów, ale stały ciąg znaków .operator == z drugiej strony. – wigy

6

Operatory są zdefiniowane jako metody statyczne, więc nie mogą uczestniczyć w polimorfizmie. Tak więc twoje drugie twierdzenie używa definicji == dla object (ponieważ twoje zmienne są zadeklarowane jako object), które testują tylko równość odniesienia. Jeśli zmienne zostałyby zadeklarowane jako string, użyto przeciążenia == dla string, a drugie potwierdzenie powiodło się.

+2

Warto również zwrócić uwagę na kompletność, że statyczne 'object.Equals (apple, orange)' zwróci 'true' w tym przypadku. 'object.Equals' najpierw używa' == 'do sprawdzania równości ref, a jeśli to się nie powiedzie, użyje przeciążonego' apple.Equals (orange) '(zakładając, że' apple' i 'orange' nie mają wartości' null'). – LukeH

+0

Rozumiem, że używam 'static bool Object.operator == (Object, Object)'. Ale nadal nie rozumiem, dlaczego to nie nazywa "Object.Equals (Object)". Ponieważ jest to wirtualne, na końcu zostanie wywołany poprawny 'String.Equals (Object)'. – wigy

Powiązane problemy