Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Sugerencia
Este artículo forma parte de la sección Aspectos básicos de los desarrolladores que ya conocen al menos un lenguaje de programación y están aprendiendo C#. Si no está familiarizado con la programación, comience primero con los tutoriales de introducción .
¿Viene de otro idioma? En Java, == en objetos y JavaScript === en objetos prueban identidad, no contenido. Las clases de C# funcionan de la misma manera de forma predeterminada. En Python, == llama __eq__ y prueba el contenido de forma predeterminada, de forma similar a la comparación de registros de C#. Las estructuras de C# también se comparan por valor cuando se llama a Equals.
C# distingue dos tipos de igualdad. La igualdad de valores significa que dos instancias son iguales cuando sus datos coinciden. La igualdad de referencia significa que dos variables son iguales solo cuando apuntan al mismo objeto en memoria. Esta condición también se denomina identidad. Normalmente, los tipos de valor comparan los datos y los tipos de referencia suelen comparar la identidad. Los autores de tipos pueden cambiar esos valores predeterminados, pero ese modelo mental evita errores sutiles en los que dos objetos que parecen idénticos no se consideran iguales o donde una mutación a través de una variable cambia silenciosamente lo que ve otra variable.
Tipos de valor, tipos de referencia y valores predeterminados de igualdad
Cada tipo de C# es un tipo de valor o un tipo de referencia. Un tipo de valor contiene sus datos directamente en la variable. Un tipo de referencia contiene una referencia a un objeto . Al asignar una variable de tipo de referencia a otra variable, ambas variables hacen referencia al mismo objeto. Para obtener más información sobre los tipos de valor y los tipos de referencia, consulte Introducción al sistema de tipos.
El comportamiento de igualdad predeterminado suele seguir el tipo de tipo:
-
Los tipos numéricos y enumeraciones integrados son tipos de valor. Dos
intvariables son iguales cuando sus valores numéricos coinciden. -
Las estructuras son tipos de valor. Un
structsimple usa la igualdad de valores al llamar a Equals. - Las tuplas son tipos de valor. Dos tuplas son iguales cuando coinciden los valores de todos sus elementos.
-
Las clases son tipos de referencia. Una clase simple usa la igualdad por referencia, por lo que
==y Equals comprueban si dos variables apuntan al mismo objeto.
Una clase usa la igualdad de referencia. Dos objetos independientes con los mismos datos no son iguales, pero dos variables que hacen referencia al mismo objeto son iguales:
var order1 = new Order(42, "Shoes");
var order2 = new Order(42, "Shoes");
Console.WriteLine(order1 == order2); // => False
Console.WriteLine(order1.Equals(order2)); // => False
Console.WriteLine(ReferenceEquals(order1, order2)); // => False
Order order3 = order1;
Console.WriteLine(order1 == order3); // => True
Un struct muestra la igualdad de valores mediante Equals. Dos instancias de estructura son iguales cuando sus campos coinciden:
var pt1 = new Point(3, 4);
var pt2 = new Point(3, 4);
Console.WriteLine(pt1.Equals(pt2)); // => True
Las estructuras simples no tienen un operador predefinido ==. Escribir p1 == p2 en un struct simple solo compila si el struct declara su propio operator ==. Si necesita comparaciones de operadores para una estructura, defina == y != como par y mantenga la coherencia con Equals y GetHashCode.
Las tuplas también son tipos de valor. Dos tuplas son iguales cuando el valor de cada elemento coincide. Los nombres de los elementos de una tupla con nombre se utilizan por simple comodidad en la compilación y no se tienen en cuenta en la comparación. Solo importan las posiciones y los valores:
var t1 = (Name: "Grace", Role: "Engineer");
var t2 = (Name: "Grace", Role: "Engineer");
Console.WriteLine(t1 == t2); // => True
Para obtener más información sobre la sintaxis de las tuplas y la deconstrucción, consulte Tuplas y deconstrucción.
Uso Object.ReferenceEquals para probar la identidad directamente
ReferenceEquals siempre comprueba la identidad independientemente de cómo un tipo invalida Equals o sobrecarga ==. Úselo como diagnóstico de identidad cuando necesite confirmar si dos variables apuntan al mismo objeto exactamente:
var doc1 = new Document("Report");
var doc2 = new Document("Report");
var doc3 = doc1;
Console.WriteLine(ReferenceEquals(doc1, doc2)); // => False
Console.WriteLine(ReferenceEquals(doc1, doc3)); // => True
Un uso habitual es dentro de una sobrescritura de Equals para evitar la comparación completa: cuando ambos argumentos son la misma referencia, siempre son iguales sin comprobar cada campo por separado.
Nota:
Cuando las variables se escriben como una interfaz, == comprueba si las variables de interfaz hacen referencia al mismo objeto. Una llamada a Equals todavía ejecuta la implementación del objeto subyacente.
Nota:
ReferenceEquals siempre devuelve false al comparar tipos de valor, incluso si ambos argumentos contienen los mismos valores. Este comportamiento se produce porque cada argumento de tipo valor se encuadra independientemente en un objeto independiente en el montón cuando se pasa a ReferenceEquals.
Los tipos pueden definir una semántica de igualdad diferente
Los tipos pueden definir la semántica de igualdad que difiere del comportamiento predeterminado. La razón más común es implementar la igualdad de valores. Si crea un tipo que representa datos, como una cuenta bancaria, un producto en el inventario o un usuario de un sistema, considere las instancias con los mismos valores que iguales. Elija los tipos de registro para implementar la igualdad de valores y el compilador generará todos los miembros de igualdad necesarios.
Nota:
Las cadenas son clases, pero == y Equals comparan contenido de cadena, no identidad.
-
==: el operador de igualdad. La mayoría de los tipos usan este operador como comprobación de igualdad principal. Su comportamiento depende de si el tipo tiene un operador==integrado o definido por el usuario. -
!=: el operador de desigualdad. Cuando un tipo define un operador definido por el usuario==, también debe definir!=. - Equals: método virtual heredado por cada tipo. Puede sobrescribirlo para cambiar la semántica de igualdad para un tipo.
- GetHashCode: un método virtual utilizado por colecciones basadas en hash. Cuando dos valores son iguales, sus códigos hash también deben ser iguales.
- ReferenceEquals: un método estático que siempre prueba la identidad.
Uso de registros para la igualdad de valores
Use el modificador record para proporcionar una igualdad de valor de tipo centrado en datos cuando el tipo pueda ser un registro. El compilador genera los miembros Equals, GetHashCode y ==/!= que comparan el valor de cada propiedad declarada.
Un record class sigue siendo un tipo de referencia, pero compara valores en lugar de identidad:
var person1 = new Person("Ada", "Lovelace");
var person2 = new Person("Ada", "Lovelace");
Console.WriteLine(person1 == person2); // => True
Console.WriteLine(person1.Equals(person2)); // => True
Console.WriteLine(ReferenceEquals(person1, person2)); // => False
ReferenceEquals confirma que person1 y person2 son objetos diferentes en la memoria, mientras == y Equals devuelven True porque la igualdad generada por el compilador compara los valores de propiedad.
La misma generación de compilador también se aplica a los tipos record struct:
var dim1 = new Dimension(1920, 1080);
var dim2 = new Dimension(1920, 1080);
Console.WriteLine(dim1 == dim2); // => True
Console.WriteLine(dim1.Equals(dim2)); // => True
Los tipos de registro generan todo el conjunto de igualdad para su propio tipo. Tanto los tipos record class como record struct sobrescriben Equals y GetHashCode. También generan los operadores == y !=, además de un método Equals tipado para el tipo de registro. A diferencia de un struct simple, un record struct admite por lo tanto == y != automáticamente. Para obtener más información sobre los tipos de registro y su semántica de igualdad, vea Registros.
Registros con miembros de tipo de referencia
La igualdad entre registros se basa en la semántica de igualdad de sus propios miembros. Cada propiedad o campo se compara mediante su propio Equals método. Para la mayoría de los valores escalares, como int, stringo DateTime, este enfoque compara los valores de los miembros de registro. La sutileza surge con colecciones mutables comunes como List<T> o T[]: estos tipos comparan por referencia, por lo que dos instancias de registro que contienen objetos de lista diferentes con el mismo contenidono se consideran iguales por la igualdad de registros sintetizada.
var playlist1 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
var playlist2 = new Playlist("Chill", new List<string> { "Song A", "Song B" });
Console.WriteLine(playlist1.Equals(playlist2)); // => False (different List instances)
Console.WriteLine(playlist1.Tracks.SequenceEqual(playlist2.Tracks)); // => True
playlist1 y playlist2 son instancias independientes List<string> . Aunque su contenido coincida, Equals devuelve false.
Cuando necesite la igualdad de registros para reflejar el contenido de la colección, tiene algunas opciones:
-
Implemente
IEquatable<T>sobre el registro y sobrescribaEqualspara usar Enumerable.SequenceEqual para los miembros de la colección. -
Use un tipo de colección con igualdad por valor — por ejemplo, un
IEqualityComparer<T>personalizado o un tipo cuyoEqualscompara los elementos. - Diseño alrededor de la identidad: si el registro representa una entidad en lugar de un valor puro, la igualdad de referencia para sus miembros de colección podría ser intencionada.
Importante
La implementación manual de la igualdad es poco frecuente en C#. Los registros controlan automáticamente el escenario común de igualdad de valores. Si tiene que implementar la igualdad manualmente —por ejemplo, porque el tipo debe derivar de una clase base que no sea un tipo de registro—, consulte Implemente la igualdad usted mismo cuando un tipo no puede ser un registro en la referencia del lenguaje.
Véase también
- Introducción al sistema de tipos
- Clases
- Estructuras
- Registros
- Tuplas y deconstrucción.
- Operadores de igualdad (referencia del lenguaje) .
- Igualdad en jerarquías de clases : instrucciones avanzadas sobre la igualdad polimórfica.
- Operadores aritméticos, de comparación, lógicos y de asignación : la encuesta de operadores de igualdad junto con operadores aritméticos, lógicos y de asignación.