0Pricing
C# Academy · Lezione

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

Verifica rapida: per dare a una classe un'uguaglianza per valore che funzioni in HashSet e Dictionary, che cosa occorre implementare?

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

  1. HashSet , SortedSet , Queue , Stack
  2. ConcurrentDictionary , raccolte immutabili
  3. Uguaglianza e hashing (valore e riferimento)
← Torna a C# Academy