¿Son realmente iguales los operadores string.Equals() y ==? [duplicar]

Resuelto miliu asked hace 14 años • 0 respuestas

¿Son realmente iguales? Hoy me encontré con este problema. Aquí está el volcado de la ventana Inmediato:

?s 
"Category" 
?tvi.Header 
"Category" 
?s == tvi.Header 
false 
?s.Equals(tvi.Header) 
true 
?s == tvi.Header.ToString() 
true 

Entonces, ambos scontienen tvi.Header"Categoría", pero ==devuelven falso y Equals()verdadero.

sse define como una cadena, tvi.Headeren realidad es un WPF TreeViewItem.Header. Entonces, ¿por qué arrojan resultados diferentes? Siempre pensé que eran intercambiables en C#.

¿Alguien puede explicar por qué es esto?

miliu avatar Sep 10 '10 00:09 miliu
Aceptado

Dos diferencias:

  • Equalses polimórfico (es decir, se puede anular y la implementación utilizada dependerá del tipo de tiempo de ejecución del objeto de destino), mientras que la implementación de ==used se determina en función de los tipos de tiempo de compilación de los objetos:

      // Avoid getting confused by interning
      object x = new StringBuilder("hello").ToString();
      object y = new StringBuilder("hello").ToString();
      if (x.Equals(y)) // Yes
    
      // The compiler doesn't know to call ==(string, string) so it generates
      // a reference comparision instead
      if (x == y) // No
    
      string xs = (string) x;
      string ys = (string) y;
    
      // Now *this* will call ==(string, string), comparing values appropriately
      if (xs == ys) // Yes
    
  • Equalslanzará una excepción si lo llamas en nulo, == no lo hará

      string x = null;
      string y = null;
    
      if (x.Equals(y)) // NullReferenceException
    
      if (x == y) // Yes
    

Tenga en cuenta que puede evitar que esto último sea un problema utilizando object.Equals:

if (object.Equals(x, y)) // Fine even if x or y is null
Jon Skeet avatar Sep 09 '2010 17:09 Jon Skeet

Las aparentes contradicciones que aparecen en la pregunta se deben a que en un caso la Equalsfunción se llama sobre un stringobjeto y en el otro caso el ==operador se llama sobre el System.Objecttipo. stringe objectimplementar la igualdad de manera diferente entre sí (valor versus referencia respectivamente).

Más allá de este hecho, cualquier tipo puede definirse ==y Equalsde forma diferente, por lo que en general no son intercambiables.

A continuación se muestra un ejemplo double(de la nota de Joseph Albahari al §7.9.2 de la especificación del lenguaje C#):

double x = double.NaN;
Console.WriteLine (x == x);         // False
Console.WriteLine (x != x);         // True
Console.WriteLine (x.Equals(x));    // True

Continúa diciendo que el double.Equals(double)método fue diseñado para funcionar correctamente con listas y diccionarios. El ==operador, por otro lado, fue diseñado para seguir el estándar IEEE 754 para tipos de punto flotante.

En el caso específico de determinar la igualdad de cadenas, la preferencia de la industria es no usar ==ni string.Equals(string)la mayor parte del tiempo. Estos métodos determinan si dos cadenas tienen el mismo carácter por carácter, lo que rara vez es el comportamiento correcto. Es mejor utilizar string.Equals(string, StringComparison), que le permite especificar un tipo particular de comparación. Al utilizar la comparación correcta, puede evitar muchos errores potenciales (muy difíciles de diagnosticar).

Aquí hay un ejemplo:

string one = "Caf\u00e9";        // U+00E9 LATIN SMALL LETTER E WITH ACUTE
string two = "Cafe\u0301";       // U+0301 COMBINING ACUTE ACCENT
Console.WriteLine(one == two);                                          // False
Console.WriteLine(one.Equals(two));                                     // False
Console.WriteLine(one.Equals(two, StringComparison.InvariantCulture));  // True

Ambas cadenas en este ejemplo tienen el mismo aspecto ("Café"), por lo que esto podría ser muy difícil de depurar si se utiliza una igualdad ingenua (ordinal).

Jeffrey L Whitledge avatar Sep 09 '2010 19:09 Jeffrey L Whitledge

C# tiene dos conceptos "iguales": Equalsy ReferenceEquals. Para la mayoría de las clases que encontrará, el ==operador usa una u otra (o ambas) y generalmente solo realiza pruebas ReferenceEqualscuando se manejan tipos de referencia (pero la stringClase es una instancia en la que C# ya sabe cómo probar la igualdad de valores).

  • Equalscompara valores. (Aunque dos intvariables separadas no existen en el mismo lugar de la memoria, aún pueden contener el mismo valor).
  • ReferenceEqualscompara la referencia y devuelve si los operandos apuntan al mismo objeto en la memoria.

Código de ejemplo:

var s1 = new StringBuilder("str");
var s2 = new StringBuilder("str");
StringBuilder sNull = null;

s1.Equals(s2); // True
object.ReferenceEquals(s1, s2); // False
s1 == s2 // True - it calls Equals within operator overload
s1 == sNull // False
object.ReferenceEquals(s1, sNull); // False
s1.Equals(sNull); // Nono!  Explode (Exception)
palswim avatar Sep 09 '2010 17:09 palswim

La Headerpropiedad de TreeViewItemestá tipificada estáticamente para ser de tipo object.

Por lo tanto los ==rendimientos false. Puedes reproducir esto con el siguiente fragmento simple:

object s1 = "Hallo";

// don't use a string literal to avoid interning
string s2 = new string(new char[] { 'H', 'a', 'l', 'l', 'o' });

bool equals = s1 == s2;         // equals is false
equals = string.Equals(s1, s2); // equals is true
Dirk Vollmar avatar Sep 09 '2010 17:09 Dirk Vollmar

Además de la respuesta de Jon Skeet , me gustaría explicar por qué la mayoría de las veces, cuando se usa, ==se obtiene la respuesta trueen diferentes instancias de cadena con el mismo valor:

string a = "Hell";
string b = "Hello";
a = a + "o";
Console.WriteLine(a == b);

Como puede ver, adeben bser instancias de cadena diferentes, pero debido a que las cadenas son inmutables, el tiempo de ejecución utiliza el llamado internamiento de cadenas para permitir que ambas ahagan breferencia a la misma cadena en la memoria. El ==operador de objetos verifica la referencia y, dado que ambos ay bhacen referencia a la misma instancia, el resultado es true. Cuando cambia cualquiera de ellos, se crea una nueva instancia de cadena, razón por la cual es posible la internación de cadenas.

Por cierto, la respuesta de Jon Skeet no está completa. De hecho, x == ylo es , falsepero eso es sólo porque está comparando objetos y los objetos se comparan por referencia. Si escribes (string)x == (string)y, volverá truede nuevo. Entonces las cadenas tienen su operador == - sobrecargado, que llama String.Equalsdebajo.

Daniel A.A. Pelsmaeker avatar Sep 09 '2010 17:09 Daniel A.A. Pelsmaeker