¿Qué tipo de miembros deberían usarse en una implementación GetHashCode ()?

7

Estamos creando algunos analizadores de Roslyn relativos a GetHashCode() , incluido un analizador que lo implementa en una clase determinada.

Al investigar el tema, hemos encontrado que hay muchas consideraciones a tener en cuenta, principalmente sobre qué tipo de miembros se deben evitar en una implementación GetHashCode() .

El tipo principal de miembro a evitar son miembros mutables (para evitar cambios de código hash cuando se usan en una colección).

  

En general, para los tipos de referencia mutables, debe reemplazar GetHashCode solo si:

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

[Source]

Ahora queda la pregunta: ¿de qué tipo de miembros estamos hablando? El miembro debe ser inmutable, pero también debe ser (idealmente) diferente para cada instancia, de lo contrario, acabará con el mismo código hash para cada objeto.

Esto me lleva a la conclusión de que los únicos miembros aceptables para una implementación de GetHashCode() son readonly inmutable structs y readonly inmutable classes Nota: no const . Del mismo modo, no hay campos static , ya que de todos modos serían iguales en todas las instancias.

La forma en que esto se implementaría en la realidad sería utilizando un

  • campo: readonly T myField
  • Propiedad: T myProp { get; }

Dado que no sería muy factible detectar si una clase es inmutable, probablemente deberíamos eliminarlo por completo, aparte de string quizás.

Esto deja la lista de miembros aplicables para una implementación GetHashCode() a:

  • Campos de solo lectura
  • Y propiedades solo para el usuario
  • que son estructuras inmutables
  • Y no son static
  • Y no son interfaces
  • + string

¿Eso parece correcto o me he equivocado en el proceso de pensamiento en alguna parte? Parece que de repente nos quedamos con mucho menos campos de los que las personas suelen usar. Me doy cuenta de que hay un aspecto pragmático que dice "agregue todos los campos y deje que el desarrollador lo descubra", pero trato de evitar la introducción de errores ocultos en los analizadores.

    
pregunta Jeroen Vannevel 04.05.2016 - 21:56

1 respuesta

4
  

Campos de solo lectura

Esto no hace falta decirlo.

  

Y propiedades solo de obtención

Sí, siempre y cuando por "propiedades solo de captador" estrictamente queremos decir type prop { get; }

  

Que son estructuras inmutables

Sí, en el sentido de que en C # las primitivas también se implementan como estructuras inmutables.

  

Y no son estáticos

Esto no hace falta decirlo.

  

Y no son interfaces

Esto no hace falta decirlo, pero tenga en cuenta que siempre puede incluir el código hash de identidad de una interfaz si lo necesita.

  
  • cadena
  •   

De nuevo, no hace falta decirlo.

El hecho de que se esté preguntando mucho sobre cómo implementar GetHashCode() puede ser indicativo de confusión sobre cuándo implementar GetHashCode() y cuándo no. Hay dos tipos de objetos:

  • Objetos con semántica de valor
  • Objetos con semántica de referencia ("objeto").

Los objetos con semántica de valor se utilizan para almacenar valores. Siempre deben ser inmutables y siempre deben implementar GetHashCode() teniendo en cuenta a cada uno de sus miembros.

Los objetos con semántica de referencia contienen lógica, y generalmente algún estado. Por lo general, no serán inmutables (aunque es posible en circunstancias excepcionales), pero una cosa que es cierta es que nunca se usarán como valores, por lo tanto, nunca deben anular el valor predeterminado GetHashCode() implementación de object , que devuelve el código hash de identidad del objeto.

    
respondido por el Mike Nakis 04.05.2016 - 23:00

Lea otras preguntas en las etiquetas