Uguaglianza e hashing (valore e riferimento)
Comprendete l’uguaglianza per riferimento e per valore, eseguite correttamente l’override di Equals/GetHashCode, implementate IEquatable e usate comparer personalizzati con insiemi e dizionari.
Uguaglianza e hashing (valore e riferimento) è una lezione C# Academy gratuita su CoddyKit. Questa è la lezione 3 di 3. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento C# Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso C# Academy include 3 lezioni in totale.
Fondamenti dell'uguaglianza
Obiettivo: fare in modo che l'uguaglianza funzioni come previsto.
- Uguaglianza per riferimento e per valore
- Contratto tra Equals e GetHashCode
- IEquatable<T> per migliorare le prestazioni
- Comparer personalizzati quando non è possibile modificare il tipo
Problema dell'uguaglianza per riferimento
Le classi usano per impostazione predefinita l'uguaglianza per riferimento. Due oggetti distinti con gli stessi dati non sono uguali, a meno che non si implementi l'uguaglianza per valore.
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)
}
}
Uguaglianza per valore implementata
Implementare IEquatable<T> ed eseguire l'override di Equals e GetHashCode. L'hash deve essere coerente con l'uguaglianza: oggetti uguali → stesso 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)
}
}
Comparer personalizzato
Passare un IEqualityComparer<T> personalizzato a HashSet/Dictionary quando non è possibile modificare direttamente il tipo.
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
}
}
Contratto e problemi comuni
Regole:
- Se Equals(a,b) è true ⇒ GetHashCode(a) == GetHashCode(b)
- L'uguaglianza dovrebbe essere riflessiva, simmetrica e transitiva
- Usare, quando possibile, campi immutabili per il calcolo dell'hash
- Non usare valori casuali in GetHashCode
Nota su struct e classi
Le struct vengono confrontate per campo per impostazione predefinita (semantica del valore). Le classi vengono confrontate per riferimento, a meno che non si implementi l'uguaglianza per valore.
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)
}
}
Contratto di uguaglianza per le raccolte
Riepilogo
Riepilogo: per ottenere la semantica del valore, le classi richiedono Equals/GetHashCode e spesso anche IEquatable<T>; usare comparer personalizzati quando i tipi non sono modificabili.
Domande Frequenti
La lezione «Uguaglianza e hashing (valore e riferimento)» è gratuita?
Sì — il testo completo di «Uguaglianza e hashing (valore e riferimento)» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso C# Academy, passa a CoddyKit PRO. Il corso C# Academy include 3 lezioni in totale.
Cosa imparerò in «Uguaglianza e hashing (valore e riferimento)»?
Comprendete l’uguaglianza per riferimento e per valore, eseguite correttamente l’override di Equals/GetHashCode, implementate IEquatable e usate comparer personalizzati con insiemi e dizionari. Eserciti C# Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.
Ho bisogno di esperienza per iniziare C# Academy?
Non è richiesta alcuna esperienza precedente. C# Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 3 di 3.
Quanto tempo richiede la lezione «Uguaglianza e hashing (valore e riferimento)»?
La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.
Posso scrivere ed eseguire codice in questa lezione C# Academy?
Sì. Ogni lezione C# Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.
Tutte le lezioni di questo corso
- HashSet , SortedSet , Queue , Stack
- ConcurrentDictionary , raccolte immutabili
- Uguaglianza e hashing (valore e riferimento)