Questo articolo è stato tradotto automaticamente. Per visualizzare l'articolo in inglese, selezionare la casella di controllo Inglese. È possibile anche visualizzare il testo inglese in una finestra popup posizionando il puntatore del mouse sopra il testo.
Traduzione
Inglese

Metodo Object.GetHashCode ()

 

Data di pubblicazione: novembre 2016

Funge da funzione hash predefinita.

Spazio dei nomi:   System
Assembly:  mscorlib (in mscorlib.dll)

public virtual int GetHashCode()

Valore restituito

Type: System.Int32

Codice hash per l'oggetto corrente.

Codice hash è un valore numerico utilizzato per inserire e identificare un oggetto in una raccolta basata su hash, ad esempio il Dictionary<TKey, TValue> (classe), il Hashtable , classe o un tipo derivato dalla DictionaryBase classe. Il GetHashCode metodo fornisce il codice hash per algoritmi che richiedono controlli rapidi di uguaglianza di oggetti.

System_CAPS_noteNota

Per informazioni sull'utilizzo di codici hash nelle tabelle hash e alcuni algoritmi di codice hash aggiuntive, vedere il Hash Function voce di Wikipedia.

L'implementazione predefinita del metodo GetHashCode non garantisce che vengano restituiti valori univoci quando è invocato su oggetti differenti. Tuttavia, non è vero il contrario: i codici hash uguale non implicano uguaglianza di oggetti, poiché diversi oggetti (uguali) possono avere i codici hash identici. Inoltre, .NET Framework non garantisce l'implementazione predefinita del GetHashCode (metodo) e il valore di questo metodo restituisce possono variare tra le versioni di .NET Framework e piattaforme, ad esempio le piattaforme a 32 bit e 64 bit. Per questi motivi, non utilizzare l'implementazione predefinita di questo metodo come identificatore di oggetto univoco per scopi di hash. Due conseguenze seguono da questo oggetto:

  • Non si deve presupporre che i codici hash uguale implicano uguaglianza degli oggetti.

  • È consigliabile mai vengono mantenute o utilizzare un codice hash all'esterno del dominio applicazione in cui è stato creato, perché possono avere hash dello stesso oggetto tra piattaforme, processi e domini applicazione.

System_CAPS_warningAvviso

Codice hash è destinato inserimento efficiente e la ricerca nelle raccolte basate su una tabella hash. Codice hash non è un valore permanente. Per questo motivo:

  • Non serializzare i valori di codice hash o archiviarli nel database.

  • Non utilizzare il codice hash come chiave per recuperare un oggetto da una raccolta con chiave.

  • Non inviare i codici hash tra i domini applicazioni o processi. In alcuni casi, i codici hash possono essere calcolati in base al dominio per processo o per ogni applicazione.

  • Non utilizzare il codice hash anziché un valore restituito da una funzione hash di crittografia, se è necessario un hash crittografico. Per gli hash di crittografia, utilizzare una classe derivata dal System.Security.Cryptography.HashAlgorithm o System.Security.Cryptography.KeyedHashAlgorithm classe.

  • Verifica l'uguaglianza dei codici hash per determinare se due oggetti sono uguali. (Oggetti diversi possono avere codici hash identici). Per verificare l'uguaglianza, chiamare il ReferenceEquals o Equals metodo.

Il GetHashCode metodo può essere sovrascritto da un tipo derivato. Se GetHashCode è non sottoposto a override, codici hash per i tipi di riferimento vengono calcolati chiamando il Object.GetHashCode metodo della classe base, che calcola un codice hash basato sul riferimento a un oggetto; per ulteriori informazioni, vedere RuntimeHelpers.GetHashCode. In altre parole, due oggetti per i quali il ReferenceEquals restituisce true codici hash identici. Se i tipi di valore esegue l'override GetHashCode, ValueType.GetHashCode metodo della classe di base utilizza la reflection per calcolare il codice hash in base ai valori dei campi del tipo. In altre parole, i cui campi hanno valori uguali i tipi di valore sono i codici hash uguale. Per ulteriori informazioni sull'override GetHashCode, vedere la sezione "Note per gli eredi".

System_CAPS_warningAvviso

Se esegue l'override di GetHashCode metodo, di eseguire l'override Equalse viceversa. Se sottoposto a override Equals restituisce true quando due oggetti sono testati per verificarne l'uguaglianza, sottoposto a override GetHashCode metodo deve restituire lo stesso valore per i due oggetti.

Se un oggetto che viene utilizzato come chiave in una tabella hash non fornisce un'implementazione utile di GetHashCode, è possibile specificare un provider di codice hash, fornendo un IEqualityComparer implementazione a uno degli overload di Hashtable costruttore della classe.

Quando si chiama il GetHashCode metodo in una classe di Windows Runtime, fornisce il comportamento predefinito per le classi che non esegue l'override GetHashCode. Ciò fa parte del supporto fornito da .NET Framework per Windows Runtime (vedere Supporto .NET Framework per applicazioni Windows Store e Windows Runtime. Classi di Windows Runtime non ereditano Objecte non implementano un GetHashCode. Tuttavia, sembrano disporre ToString, Equals(Object), e GetHashCode metodi quando utilizzarle nel codice c# o Visual Basic e .NET Framework fornisce il comportamento predefinito per questi metodi.

System_CAPS_noteNota

Windows Runtimele classi che vengono scritti in c# o Visual Basic possono eseguire l'override di GetHashCode metodo.

Note per gli eredi:

Le implementazioni del metodo GetHashCode non devono produrre come risultato dei riferimenti circolari. Le funzioni hash vengono in genere specifiche per ogni tipo e l'univocità, devono utilizzare almeno uno dei campi di istanza come input. I codici hash non può essere calcolati utilizzando i valori dei campi statici.

Per le classi derivate da Object, GetHashCode metodo può delegare alla classe di base Object.GetHashCode() implementazione solo se la classe derivata definisce l'uguaglianza di valori di uguaglianza. L'implementazione predefinita di GetHashCode per riferimento tipi restituisce un codice hash che corrisponde a quello restituito dal RuntimeHelpers.GetHashCode(Object) metodo. È possibile eseguire l'override GetHashCode per i tipi di riferimento non modificabile. In generale, per i tipi di riferimento modificabile, è necessario eseguire l'override GetHashCode solo se:

  • È possibile calcolare il codice hash dai campi che non sono modificabili; o

  • È possibile garantire che il codice hash di un oggetto modificabile non modificato mentre l'oggetto è contenuto in una raccolta che si basa il codice hash.

In caso contrario, si potrebbe pensare che l'oggetto modificabile viene perso nella tabella hash. Se si sceglie di eseguire l'override GetHashCode per un tipo di riferimento modificabile, la documentazione di inoltre deve essere chiaro che gli utenti del tipo non devono modificare i valori di oggetto mentre l'oggetto viene archiviato in una tabella hash.

Per i tipi di valore, ValueType.GetHashCode fornisce un'implementazione di codice hash predefinito che utilizza la reflection. È consigliabile eseguirne l'override per ottenere prestazioni migliori.

System_CAPS_noteNota

Per ulteriori informazioni ed esempi che consentono di calcolare i codici hash in diversi modi, vedere la sezione esempi.

Una funzione hash deve avere le proprietà seguenti:

  • Se due oggetti vengono considerati uguali, il GetHashCode metodo per ogni oggetto deve restituire lo stesso valore. Tuttavia, se due oggetti non vengono considerati uguali, il GetHashCode metodi per i due oggetti non è necessario restituire valori diversi.

  • Il GetHashCode metodo per un oggetto in modo coerente deve restituire lo stesso codice hash fino a quando non viene modificato per lo stato dell'oggetto che determina il valore restituito dell'oggetto Equals metodo. Si noti che questo vale solo per l'esecuzione corrente di un'applicazione e che può essere restituito un codice hash diverso se si esegue nuovamente l'applicazione.

  • Per ottenere prestazioni ottimali, una funzione hash deve generare una distribuzione uniforme per tutti gli input, tra cui input frequentemente in cluster. Un'implicazione è che le modifiche di grandi dimensioni per il codice hash risultante per ottimizzare le prestazioni di tabella hash devono comportare piccole modifiche allo stato dell'oggetto.

  • Le funzioni hash devono essere basso costo per il calcolo.

  • Il GetHashCode (metodo) non devono generare eccezioni.

Ad esempio, l'implementazione del GetHashCode fornito dal metodo di String classe restituisce codici hash identici per i valori di stringa identica. Pertanto, due String oggetti restituiscono lo stesso codice hash se rappresentano lo stesso valore di stringa. Inoltre, il metodo utilizza tutti i caratteri nella stringa di generare output distribuiti ragionevolmente in modo casuale, anche quando l'input è un indice cluster in determinati intervalli (ad esempio, molti utenti potrebbero produrre stringhe che contengono solo gli inferiore 128 caratteri ASCII, anche se una stringa può contenere i caratteri Unicode 65.535).

Fornisce una funzione hash valida in una classe può influire in modo significativo le prestazioni di aggiunta di tali oggetti in una tabella hash. In una tabella hash con chiavi che forniscono l'implementazione di una funzione hash, la ricerca di un elemento tempo costante (ad esempio, un'operazione o (1)). In una tabella hash con una scarsa implementazione di una funzione hash, le prestazioni di una ricerca dipendono dal numero di elementi nella tabella hash (ad esempio, un'operazione O (n) operazione, in cui n è il numero di elementi nella tabella hash). Un utente malintenzionato può immettere dati che aumenta il numero di conflitti, che può ridurre significativamente le prestazioni delle applicazioni che dipendono da tabelle hash, le seguenti condizioni:

  • Quando le funzioni hash generano conflitti frequenti.

  • Gran parte degli oggetti in una tabella hash producono quando i codici hash che sono uguali o approssimativamente uguale uno a altro.

  • Quando gli utenti di input i dati da cui viene calcolato il codice hash.

Le classi derivate che eseguire l'override GetHashCode deve anche eseguire l'override Equals per garantire che i due oggetti considerati uguali abbiano lo stesso codice hash; in caso contrario, il Hashtable tipo potrebbe non funzionare correttamente.

Uno dei modi più semplici per calcolare un codice hash per un valore numerico con lo stesso o un intervallo più piccolo rispetto al Int32 tipo è semplicemente restituire tale valore. Nell'esempio seguente viene illustrato tale implementazione per un Number struttura.

using System;

public struct Number
{
   private int n;

   public Number(int value)
   {
      n = value;
   }

   public int Value
   {
      get { return n; }
   }

   public override bool Equals(Object obj)
   {
      if (obj == null || ! (obj is Number)) 
         return false;
      else
         return n == ((Number) obj).n;
   }      

   public override int GetHashCode()
   {
      return n;
   }

   public override string ToString()
   {
      return n.ToString();
   }
}

public class Example
{
   public static void Main()
   {
      Random rnd = new Random();
      for (int ctr = 0; ctr <= 9; ctr++) {
         int randomN = rnd.Next(Int32.MinValue, Int32.MaxValue);
         Number n = new Number(randomN);
         Console.WriteLine("n = {0,12}, hash code = {1,12}", n, n.GetHashCode());
      }   
   }
}
// The example displays output like the following:
//       n =   -634398368, hash code =   -634398368
//       n =   2136747730, hash code =   2136747730
//       n =  -1973417279, hash code =  -1973417279
//       n =   1101478715, hash code =   1101478715
//       n =   2078057429, hash code =   2078057429
//       n =   -334489950, hash code =   -334489950
//       n =    -68958230, hash code =    -68958230
//       n =   -379951485, hash code =   -379951485
//       n =    -31553685, hash code =    -31553685
//       n =   2105429592, hash code =   2105429592

Spesso, un tipo dispone di più campi di dati che possono partecipare alla generazione di codice hash. Per generare un codice hash è possibile combinare questi campi utilizzando un XOR (eXclusive OR) operazione, come illustrato nell'esempio seguente.

using System;

// A type that represents a 2-D point.
public struct Point
{
    private int x;
    private int y;

    public Point(int x, int y)
    {
       this.x = x;
       this.y = y;
    }

    public override bool Equals(Object obj)
    {
       if (! (obj is Point)) return false;

       Point p = (Point) obj;
       return x == p.x & y == p.y;
    }

    public override int GetHashCode()
    { 
        return x ^ y;
    } 
} 

public class Example
{
   public static void Main()
   {
      Point pt = new Point(5, 8);
      Console.WriteLine(pt.GetHashCode());

      pt = new Point(8, 5);
      Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays the following output:
//       13
//       13

L'esempio precedente restituisce lo stesso codice hash per (n1, n2) e (n2, n1) e pertanto può generare più collisioni di è auspicabile. Un numero di soluzioni è disponibile in modo che i codici hash in questi casi non sono identici. Per restituire il codice hash di cui uno è un Tuple oggetto che corrisponde all'ordine di ogni campo. Nell'esempio seguente viene illustrata una possibile implementazione che utilizza il Tuple<T1, T2> classe. Si noti tuttavia che l'overhead delle prestazioni di un'istanza di un Tuple oggetto può influire notevolmente sulle prestazioni complessive di un'applicazione che memorizza un numero elevato di oggetti nelle tabelle hash.

using System;

public struct Point
{
    private int x;
    private int y;

    public Point(int x, int y)
    {
       this.x = x;
       this.y = y;
    }

    public override bool Equals(Object obj)
    {
       if (!(obj is Point)) return false;

       Point p = (Point) obj;
       return x == p.x & y == p.y;
    }

    public override int GetHashCode()
    { 
        return Tuple.Create(x, y).GetHashCode();
    } 
} 

public class Example
{
   public static void Main()
   {
        Point pt = new Point(5, 8);
        Console.WriteLine(pt.GetHashCode());

        pt = new Point(8, 5);
        Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays the following output:
//       173
//       269

Una seconda soluzione alternativa prevede ponderazione i codici hash singoli da spostamento a sinistra i codici hash di successivi campi di bit di due o più. In modo ottimale, invece di essere eliminato, i bit spostati oltre a 31 bit devono eseguire il wrapping intorno anziché ignorati. Poiché bit vengono rimossi dagli operatori di spostamento a sinistra in c# e Visual Basic, questa operazione richiede creazione di un metodo shift a capo sinistro simile al seguente:

public int ShiftAndWrap(int value, int positions)
{
    positions = positions & 0x1F;

    // Save the existing bit pattern, but interpret it as an unsigned integer.
    uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
    // Preserve the bits to be discarded.
    uint wrapped = number >> (32 - positions);
    // Shift and wrap the discarded bits.
    return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);
}

L'esempio seguente usa quindi questo metodo shift a capo per calcolare il codice hash del Point struttura utilizzata negli esempi precedenti.

using System;

public struct Point
{
    private int x;
    private int y;

    public Point(int x, int y)
    {
       this.x = x;
       this.y = y;
    }

    public override bool Equals(Object obj)
    {
       if (!(obj is Point)) return false;

       Point p = (Point) obj;
       return x == p.x & y == p.y;
    }

    public override int GetHashCode()
    { 
        return ShiftAndWrap(x.GetHashCode(), 2) ^ y.GetHashCode();
    } 

    private int ShiftAndWrap(int value, int positions)
    {
        positions = positions & 0x1F;

        // Save the existing bit pattern, but interpret it as an unsigned integer.
        uint number = BitConverter.ToUInt32(BitConverter.GetBytes(value), 0);
        // Preserve the bits to be discarded.
        uint wrapped = number >> (32 - positions);
        // Shift and wrap the discarded bits.
        return BitConverter.ToInt32(BitConverter.GetBytes((number << positions) | wrapped), 0);
    }
} 

public class Example
{
   public static void Main()
   {
        Point pt = new Point(5, 8);
        Console.WriteLine(pt.GetHashCode());

        pt = new Point(8, 5);
        Console.WriteLine(pt.GetHashCode());
   }
}
// The example displays the following output:
//       28
//       37 

Universal Windows Platform
Disponibile da 8
.NET Framework
Disponibile da 1.1
Libreria di classi portabile
Supportato in: piattaforme .NET portabili
Silverlight
Disponibile da 2.0
Windows Phone Silverlight
Disponibile da 7.0
Windows Phone
Disponibile da 8.1
Torna all'inizio
Mostra: