Este artículo se tradujo automáticamente. Para ver el artículo en inglés, active la casilla Inglés. Además, puede mostrar el texto en inglés en una ventana emergente si mueve el puntero del mouse sobre el texto.
Traducción
Inglés

Método Object.GetHashCode ()

 

Publicado: noviembre de 2016

Sirve como la función hash predeterminada.

Espacio de nombres:   System
Ensamblado:  mscorlib (en mscorlib.dll)

public virtual int GetHashCode()

Valor devuelto

Type: System.Int32

Código hash para el objeto actual.

Un código hash es un valor numérico que se utiliza para insertar e identificar un objeto de una colección basado en hash como el Dictionary<TKey, TValue> (clase), el Hashtable clase o un tipo derivado de la DictionaryBase clase. El método GetHashCode proporciona este código hash para los algoritmos que necesitan comprobaciones rápidas de igualdad de objetos.

System_CAPS_noteNota

Para obtener información sobre cómo se utilizan los códigos hash en tablas hash y para algunos algoritmos de código hash adicionales, consulte la Hash Function entrada de Wikipedia.

La implementación por defecto del método GetHashCode no garantiza la devolución de valores únicos para distintos objetos. Sin embargo, lo contrario no es cierto: códigos hash igual no conllevan la igualdad de objetos, porque los objetos (iguales) diferentes pueden tener códigos hash idénticos. Además, .NET Framework no garantiza la implementación predeterminada de la GetHashCode (método) y el valor de este método devuelve pueden diferir entre versiones de .NET Framework y las plataformas, como las plataformas de 32 bits y 64 bits. Por estos motivos, no use la implementación predeterminada de este método como un identificador de objeto único para fines de hash. Siguen dos consecuencias de esto:

  • No se debe suponer que los códigos hash igual implican igualdad de objetos.

  • Nunca debería conservar o utilizar un código hash fuera del dominio de aplicación en el que se creó, porque el mismo objeto puede hash entre plataformas, procesos y dominios de aplicación.

System_CAPS_warningAdvertencia

Un código hash está destinado a una inserción y búsqueda en las colecciones que se basan en una tabla hash. Un código hash no es un valor permanente. Por esta razón:

  • No serializar los valores de código hash o almacenarlos en las bases de datos.

  • No utilice el código hash como clave para recuperar un objeto de una colección con clave.

  • No se envían códigos hash a través de procesos o dominios de aplicación. En algunos casos, se pueden calcular los códigos hash de forma dominio por proceso o por aplicación.

  • No utilice el código hash en lugar de un valor devuelto por una función hash criptográfica si necesita un hash criptográficamente seguro. Para valores hash criptográficos, utilice una clase derivada de la System.Security.Cryptography.HashAlgorithm o System.Security.Cryptography.KeyedHashAlgorithm clase.

  • No comprobar la igualdad de los códigos hash para determinar si dos objetos son iguales. (Objetos distintos pueden tener códigos hash idénticos). Para comprobar la igualdad, llame a la ReferenceEquals o Equals método.

El GetHashCode método puede reemplazarse por un tipo derivado. Si GetHashCode es no se reemplaza, códigos hash para tipos de referencia se calculan mediante una llamada a la Object.GetHashCode método de la clase base, que calcula un código hash basado en la referencia de un objeto; para obtener más información, consulte RuntimeHelpers.GetHashCode. En otras palabras, dos objetos para los que el ReferenceEquals método true tienen códigos hash idénticos. Si los tipos de valor no invalidar GetHashCode, el ValueType.GetHashCode método de la clase base utiliza la reflexión para calcular el código hash basado en los valores de los campos del tipo. En otras palabras, cuyos campos tienen los mismos valores de tipos de valor tienen códigos hash igual. Para obtener más información sobre cómo invalidar GetHashCode, vea la sección "Notas para los herederos".

System_CAPS_warningAdvertencia

Si invalida el GetHashCode método, también debe invalidar Equalsy viceversa. Si su invalidado Equals método true cuando dos objetos se comprueban si hay igualdad, su invalidada GetHashCode método debe devolver el mismo valor para los dos objetos.

Si un objeto que se utiliza como clave en una tabla hash no proporciona una implementación útil de GetHashCode, puede especificar un proveedor de código hash proporcionando un IEqualityComparer implementación a una de las sobrecargas de los Hashtable constructor de clase.

Cuando se llama a la GetHashCode método en una clase en el Windows en tiempo de ejecución, proporciona el comportamiento predeterminado para las clases que no se invalidan GetHashCode. Esto forma parte de la compatibilidad que .NET Framework proporciona para Windows en tiempo de ejecución (vea Compatibilidad de .NET Framework con las aplicaciones de la Tienda Windows y Windows Runtime). Las clases en el Windows en tiempo de ejecución no heredar Objecty actualmente no se implementa un GetHashCode. Sin embargo, parece que tienen ToString, Equals(Object), y GetHashCode métodos cuando se usa en el código de C# o Visual Basic y .NET Framework proporciona el comportamiento predeterminado para estos métodos.

System_CAPS_noteNota

Windows en tiempo de ejecuciónlas clases que se escriben en C# o Visual Basic pueden invalidar la GetHashCode método.

Notas para desarrolladores de herederos:

Una función hash se utiliza para generar rápidamente un número (código hash) que corresponde al valor de un objeto. Las funciones hash suelen ser están para cada tipo y, de unicidad, deben utilizar al menos uno de los campos de instancia como entrada. No se deben calcular códigos hash mediante el uso de los valores de los campos estáticos.

Para las clases derivadas de Object, GetHashCode puede delegar el método a la clase base Object.GetHashCode() implementación sólo si la clase derivada define la igualdad para que sea la igualdad de referencia. La implementación predeterminada de GetHashCode para referencia tipos devuelve un código hash que es equivalente a la devuelta por la RuntimeHelpers.GetHashCode(Object) método. Puede invalidar GetHashCode para tipos de referencia inmutable. En general, para los tipos de referencias mutables, debe invalidar GetHashCode solo si:

  • Puede calcular el código hash de los campos que no son mutables; o

  • Puede asegurarse de que el código hash de un objeto mutable no cambia y el objeto se encuentra en una colección que se basa en el código hash.

En caso contrario, puede que piense que se ha perdido el objeto mutable en la tabla hash. Si elige reemplazar GetHashCode para un tipo de referencia mutable, la documentación debe dejar claro que los usuarios de su tipo no deben modificar los valores de objeto mientras el objeto se almacena en una tabla hash.

Para los tipos de valor, ValueType.GetHashCode proporciona una implementación del código hash predeterminado que usa la reflexión. Considere la posibilidad de reemplazar para mejorar el rendimiento.

System_CAPS_noteNota

Para obtener más información y ejemplos que calculan códigos hash en una variedad de formas, vea la sección ejemplos.

Una función hash debe tener las siguientes propiedades:

  • Si dos objetos comparan como iguales, la GetHashCode método para cada objeto debe devolver el mismo valor. Sin embargo, si dos objetos no compararse como iguales, la GetHashCode métodos para los dos objetos no tienen que devolver valores diferentes.

  • El GetHashCode método para un objeto de forma coherente debe devolver el mismo código hash como no hay ninguna modificación en el estado del objeto que determina el valor devuelto por el objeto Equals método. Tenga en cuenta que esto es cierto solo para la ejecución actual de una aplicación y que se puede devolver un código hash diferente si se vuelve a ejecutar la aplicación.

  • Para obtener el mejor rendimiento, una función hash debe generar una distribución uniforme para todas las entradas, incluida la entrada que está agrupado con un alto grado. Una implicación es que deben dar como resultado pequeñas modificaciones en el estado de objetos grandes modificaciones en el código hash resultante para un mejor rendimiento de la tabla de hash.

  • Las funciones hash deben ser económicas calcular.

  • El GetHashCode método no debe producir excepciones.

Por ejemplo, la implementación de la GetHashCode método proporcionado por el String clase devuelve códigos hash idénticos para valores de cadena idénticos. Por lo tanto, dos String objetos devuelven el mismo código hash si representan el mismo valor de cadena. Además, el método utiliza todos los caracteres en la cadena para generar la salida con una distribución aleatoria razonable, incluso cuando la entrada está en clúster en determinados intervalos (por ejemplo, muchos usuarios pueden tener las cadenas que contienen sólo los 128 caracteres ASCII inferiores, aunque una cadena puede contener cualquiera de los 65.535 caracteres Unicode).

Proporciona una función hash adecuada en una clase puede afectar significativamente al rendimiento de la adición de esos objetos en una tabla hash. En una tabla hash con claves que proporcionan una buena implementación de una función hash, busca un elemento tiene tiempo constante (por ejemplo, una operación o (1)). En una tabla hash con una implementación inadecuada de una función hash, el rendimiento de una búsqueda depende del número de elementos de la tabla hash (por ejemplo, una O (n) operación, donde n es el número de elementos de la tabla hash). Un usuario malintencionado puede escribir datos que aumentan el número de conflictos, que puede reducir significativamente el rendimiento de las aplicaciones que dependen de las tablas hash, en las siguientes condiciones:

  • Cuando las funciones hash producen colisiones frecuentes.

  • Cuando una gran proporción de objetos en una tabla hash generar códigos hash que son iguales o aproximadamente igual entre sí.

  • Cuando los usuarios los datos desde el que se calcula el código hash de entrada.

Las clases derivadas que invalidan GetHashCode también debe invalidar Equals para garantizar que dos objetos considerados iguales tengan el mismo código hash; en caso contrario, el Hashtable tipo no funcionen correctamente.

Una de las maneras más sencillas para calcular un código hash para un valor numérico que tiene la misma o a un intervalo más pequeño que el Int32 tipo es simplemente devolver ese valor. En el ejemplo siguiente se muestra este tipo de implementación para una Number estructura.

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

Con frecuencia, un tipo tiene varios campos de datos que pueden participar en la generación del código hash. Una manera de generar un código hash consiste en combinar estos campos utilizando una XOR (eXclusive OR) operación, tal y como se muestra en el ejemplo siguiente.

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

El ejemplo anterior devuelve el mismo código hash de (n1, n2) y (n2, n1) por lo que puede generar más colisiones de deseable. Un número de soluciones está disponible para que los códigos hash en estos casos no son idénticos. Una consiste en devolver el código hash de un Tuple objeto que refleja el orden de cada campo. En el ejemplo siguiente se muestra una posible implementación que usa el Tuple<T1, T2> clase. Sin embargo, tenga en cuenta que la sobrecarga de rendimiento de una instancia un Tuple objeto puede afectar significativamente al rendimiento general de una aplicación que almacena gran cantidad de objetos en las tablas 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 segunda solución alternativa implica la ponderación de los códigos hash individuales mediante su desplazamiento a la izquierda los códigos hash de campos sucesivas por dos o más bits. En condiciones óptimas, en lugar de descartarse, bits desplazados más allá de 31 bits se deben ajustar alrededor en lugar de descartar. Puesto que se descartan los bits por los operadores de desplazamiento a la izquierda en C# y Visual Basic, esto requiere la creación de un método de ajuste de desplazamiento a la izquierda similar al siguiente:

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);
}

En el ejemplo siguiente se utiliza, a continuación, este método de ajuste de desplazamiento para calcular el código hash de la Point estructura utilizada en los ejemplos anteriores.

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 

Plataforma universal de Windows
Disponible desde 8
.NET Framework
Disponible desde 1.1
Biblioteca de clases portable
Se admite en: plataformas portátiles de .NET
Silverlight
Disponible desde 2.0
Windows Phone Silverlight
Disponible desde 7.0
Windows Phone
Disponible desde 8.1
Volver al principio
Mostrar: