Tipos · comparación
== frente a .Equals() en C#
Coinciden en la mayoría del código de principiante — y las diferencias son justo donde se esconden los bugs: el manejo de null y qué significa "igual" para cada tipo.
Para primitivos: comportamiento idéntico
int x = 5;
int y = 5;
bool f = false;
Console.WriteLine(x == y); // comparación de valores
Console.WriteLine(x.Equals(y)); // la misma respuesta para int
Console.WriteLine(f.Equals(false));
Para int, double, bool, char no hay diferencia real — usa ==, se lee mejor.
Para strings: mismo resultado, mecanismo distinto
string a = "manzana";
Console.WriteLine(a == "manzana"); // True — C# hace que == compare CONTENIDO
Console.WriteLine(a == "Manzana"); // False — las mayúsculas importan, siempre
Console.WriteLine(a.Equals("manzana")); // True — contenido otra vez
Console.WriteLine(a.Equals("Manzana")); // False — misma regla de mayúsculas
Ambos comparan contenido y ambos distinguen mayúsculas. (En otros lenguajes == compara referencias para strings — la clásica confusión C#/Java; en C# el operador se sobrecargó para hacer lo útil.)
Diferencia 1: manejo de null
La verdadera divisoria. == convive con null; llamar a un método sobre null explota:
string s = null;
// == es una comprobación estática — null en cualquier lado está bien
Console.WriteLine(s == null);
// .Equals() es una LLAMADA a un método sobre s — s es null, así que protégelo antes:
if (s != null)
{
Console.WriteLine(s.Equals("x"));
}
else
{
Console.WriteLine("seguro"); // aquí entra — llamar a s.Equals habría lanzado
}
Regla práctica: cuando cualquiera de los lados podría ser null, usa == (o string.IsNullOrEmpty), no .Equals().
Diferencia 2: qué significa "igual" es redefinible
Equals() es un método que una clase puede redefinir; == es un operador que una clase puede o no sobrecargar. Para tus propias clases, ninguno compara contenido por defecto — ambos son identidad (la demo a == b → False del artículo struct vs class):
class Perro { public string Nombre; }
Perro d1 = new Perro { Nombre = "Rex" };
Perro d2 = new Perro { Nombre = "Rex" };
Console.WriteLine(d1 == d2); // False — objetos distintos
Console.WriteLine(d1.Equals(d2)); // False — igual, salvo que se redefina Equals
Los records (C# 9+) y los struct cambian ese valor por defecto a comparación de valores — una de las razones por las que los records se adueñaron de los tipos de datos.
El ganador del día a día: comparar sin mayúsculas
La entrada del usuario no respeta tus mayúsculas. La herramienta idiomática no es == ni Equals a secas — es Equals con un tipo de comparación (en Visual Studio; el motor del navegador aún no tiene esa sobrecarga):
string input = "SI";
// estos tres son los patrones del mundo real:
input == "si" // False — distingue mayúsculas
input.Equals("si", StringComparison.OrdinalIgnoreCase) // True
input.ToLower() == "si" // True — la versión rápida y sucia
Prefiere StringComparison.OrdinalIgnoreCase a las cadenas de ToLower() — no asigna memoria y pone la intención a la vista.
Tabla de decisión
| Comparando | Usa |
|---|---|
| números, bool, char | == |
| strings, importan mayúsculas | == |
| strings, sin mayúsculas | Equals(…, OrdinalIgnoreCase) |
| algo que podría ser null | == (o IsNullOrEmpty) |
| tus propios tipos de igualdad por contenido | hazlo record, o redefine Equals |