Igualdad y hashing (por valor frente a por referencia)
Comprenda la igualdad por referencia frente a la igualdad por valor, sobrescriba Equals/GetHashCode correctamente, implemente IEquatable y use comparadores personalizados con conjuntos y diccionarios.
Igualdad y hashing (por valor frente a por referencia) es una lección gratuita de C# Academy en CoddyKit. Esta es la lección 3 de 3. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de C# Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de C# Academy incluye 3 lecciones en total.
Fundamentos de la igualdad
Objetivo: Haga que la igualdad funcione como espera.
- Igualdad por referencia frente a igualdad por valor
- Contrato entre Equals y GetHashCode
- IEquatable<T> para mejorar el rendimiento
- Comparadores personalizados cuando no pueda modificar el tipo
Problema de la igualdad por referencia
De forma predeterminada, las clases usan la igualdad por referencia. Dos objetos independientes con los mismos datos no son iguales a menos que implemente la igualdad por valor.
using System;
using System.Collections.Generic;
public sealed class Point // no overrides
{
public int X;
public int Y;
public Point(int x, int y){ X = x; Y = y; }
}
public class Program
{
public static void Main(string[] args)
{
Point a = new Point(1, 2);
Point b = new Point(1, 2);
Console.WriteLine("a == b ? " + (a == b)); // reference equality: False
Console.WriteLine("a.Equals(b) ? " + a.Equals(b)); // False
HashSet<Point> set = new HashSet<Point>();
set.Add(a);
Console.WriteLine("Contains b? " + set.Contains(b)); // False (unexpected)
}
}
Igualdad por valor implementada
Implemente IEquatable<T> e invalide Equals y GetHashCode. El hash debe coincidir con la igualdad: los objetos iguales deben tener el mismo hash.
using System;
using System.Collections.Generic;
public sealed class ValuePoint : IEquatable<ValuePoint>
{
public int X;
public int Y;
public ValuePoint(int x, int y){ X = x; Y = y; }
public bool Equals(ValuePoint other)
{
if (ReferenceEquals(other, null)) return false;
if (ReferenceEquals(this, other)) return true;
return X == other.X && Y == other.Y;
}
public override bool Equals(object obj)
{
return Equals(obj as ValuePoint);
}
public override int GetHashCode()
{
// Simple, stable combination (avoid randomness)
unchecked
{
int hash = 17;
hash = hash * 31 + X.GetHashCode();
hash = hash * 31 + Y.GetHashCode();
return hash;
}
}
}
public class Program
{
public static void Main(string[] args)
{
ValuePoint a = new ValuePoint(1, 2);
ValuePoint b = new ValuePoint(1, 2);
Console.WriteLine("a.Equals(b)? " + a.Equals(b)); // True
HashSet<ValuePoint> set = new HashSet<ValuePoint>();
set.Add(a);
Console.WriteLine("Contains b? " + set.Contains(b)); // True (value semantics)
}
}
Comparador personalizado
Pase un IEqualityComparer<T> personalizado a HashSet/Dictionary cuando no pueda cambiar el tipo en sí.
using System;
using System.Collections.Generic;
public sealed class Person // imagine from a library; cannot edit
{
public string Name;
public int BirthYear;
public Person(string name, int year){ Name = name; BirthYear = year; }
}
public sealed class PersonComparer : IEqualityComparer<Person>
{
public bool Equals(Person a, Person b)
{
if (ReferenceEquals(a, b)) return true;
if (ReferenceEquals(a, null) || ReferenceEquals(b, null)) return false;
return a.Name == b.Name && a.BirthYear == b.BirthYear;
}
public int GetHashCode(Person p)
{
if (ReferenceEquals(p, null)) return 0;
unchecked
{
int h = 23;
h = h * 31 + (p.Name == null ? 0 : p.Name.GetHashCode());
h = h * 31 + p.BirthYear.GetHashCode();
return h;
}
}
}
public class Program
{
public static void Main(string[] args)
{
Person p1 = new Person("Ada", 1815);
Person p2 = new Person("Ada", 1815);
HashSet<Person> set = new HashSet<Person>(new PersonComparer());
set.Add(p1);
Console.WriteLine("Contains p2? " + set.Contains(p2)); // True via comparer
}
}
Contrato y errores comunes
Reglas:
- Si Equals(a,b) es true ⇒ GetHashCode(a) == GetHashCode(b)
- La igualdad debe ser reflexiva, simétrica y transitiva
- Siempre que sea posible, use campos inmutables para calcular el hash
- No use valores aleatorios en GetHashCode
Nota sobre struct y class
Las estructuras se comparan por sus campos de forma predeterminada (semántica de valor). Las clases se comparan por referencia a menos que implemente la igualdad por valor.
using System;
public struct PointS // struct: value type
{
public int X;
public int Y;
public PointS(int x, int y){ X = x; Y = y; }
}
public class Program
{
public static void Main(string[] args)
{
PointS a = new PointS(1, 2);
PointS b = new PointS(1, 2);
Console.WriteLine("Struct equality: " + a.Equals(b)); // True by default (field-wise)
}
}
Contrato de igualdad para colecciones
Resumen
Resumen: Las clases necesitan Equals/GetHashCode (y a menudo IEquatable<T>) para tener semántica de valor; use comparadores personalizados cuando no pueda editar los tipos.
Preguntas frecuentes
¿La lección «Igualdad y hashing (por valor frente a por referencia)» es gratis?
Sí — el texto completo de «Igualdad y hashing (por valor frente a por referencia)» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de C# Academy, actualiza a CoddyKit PRO. El curso de C# Academy incluye 3 lecciones en total.
¿Qué aprenderé en «Igualdad y hashing (por valor frente a por referencia)»?
Comprenda la igualdad por referencia frente a la igualdad por valor, sobrescriba Equals/GetHashCode correctamente, implemente IEquatable y use comparadores personalizados con conjuntos y diccionarios. Practicas C# Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar C# Academy?
No se requiere experiencia previa. C# Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 3.
¿Cuánto tiempo toma la lección «Igualdad y hashing (por valor frente a por referencia)»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de C# Academy?
Sí. Cada lección de C# Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- HashSet , SortedSet , Queue y Stack
- ConcurrentDictionary y colecciones inmutables
- Igualdad y hashing (por valor frente a por referencia)