c# - ¿Qué debe devolver GetHashCode cuando el identificador del objeto es nulo?
gethashcode string c# (3)
Cuál de los siguientes es correcto / mejor, considerando que la propiedad de identidad podría ser nula.
public override int GetHashCode()
{
if (ID == null) {
return base.GetHashCode();
}
return ID.GetHashCode();
}
O
public override int GetHashCode()
{
if (ID != null) {
return ID.GetHashCode();
}
return 0;
}
Actualización 1: 2ª opción actualizada.
Actualización 2: A continuación se muestran las implementaciones de Equals:
public bool Equals(IContract other)
{
if (other == null)
return false;
if (this.ID.Equals(other.ID)) {
return true;
}
return false;
}
public override bool Equals(object obj)
{
if (obj == null)
return base.Equals(obj);
if (!obj is IContract) {
throw new InvalidCastException("The ''obj'' argument is not an IContract object.");
} else {
return Equals((IContract)obj);
}
}
Y la identificación es de tipo string
.
Realmente depende de lo que quieres que signifique igualdad: lo importante es que dos objetos iguales devuelven el mismo código hash. ¿Qué significa igualdad cuando la identificación es nula? Actualmente, su método Equals tendría que devolver verdadero si las propiedades de ID tienen el mismo valor ... pero no sabemos qué hace si ID es nulo.
Si realmente quieres el comportamiento de la primera versión, yo personalmente uso:
return ID == null ? base.GetHashCode() : ID.GetHashCode();
EDITAR: basado en su método Equals, parece que podría hacer que su método GetHashCode:
return ID == null ? 0 : ID.GetHashCode();
Tenga en cuenta que su método Equals(IContract other)
también podría tener este aspecto:
return other != null && object.Equals(this.ID, other.ID);
Su implementación actual lanzará una excepción si this.ID
es nulo ...
Además, su método Equals(object)
es incorrecto: no debe lanzar una excepción si se le pasa un tipo de objeto inapropiado, solo debe devolver false
... lo mismo si obj
es nulo. Así que en realidad puedes usar:
public override bool Equals(object obj)
{
return Equals(obj as IContract);
}
Sin embargo, me preocupa la igualdad basada en una interfaz. Normalmente, dos clases de tipos diferentes no deben considerarse iguales incluso si implementan las mismas interfaces.
Simplemente puede return 0;
, debe devolver el mismo HashCode para los mismos valores y 0 no será devuelto a menudo por ID.GetHashCode (), por lo que dicha función de Hash puede estar bastante bien para cualquier necesidad. Dado que no combina ningún valor (como ID y Name Hashes), su ID bastante clara es la fuente definitoria de HashCode, por lo que el 0 fijo para el Null ID suena razonable.
De lo contrario, podría ser cierto que todo su enfoque en la anulación de GetHashCode solo teniendo en cuenta el campo de ID es incorrecto (y necesita combinar varios campos para calcular el hash de ellos)
Después de sus ediciones, puedo decir que la segunda anulación de Equals tiene demasiado código, simplemente reemplácela con
public override bool Equals(object obj)
{
return Equals(obj as Contract);
}
La anulación de su Igualdad (contrato de IContract) me parece defectuosa porque la única cosa que define el contrato es la identificación y si IContract tiene más campos que la identificación, será una anulación incorrecta de la igualdad.
PD: En realidad, si IContract es una interfaz, probablemente deba reemplazar su IEquatable<IContract>
por un IEquatable<ClassName>
concreto de IEquatable<ClassName>
ya que será un mal diseño el poder devolver que las diferentes sustancias de clase que implementan la misma interfaz sean iguales por igual. por definición, requiere verificar que los objetos tengan el mismo Tipo en la primera etapa de verificación de igualdad (generalmente en casos como el 99,9%)
Tal vez lo que quieres es algo como esto?
override int GetHashCode()
{
if (ID != null)
return ID.GetHashCode();
return DBNull.Value.GetHashCode();
}
Lo importante es esto, ¿deberían considerarse dos objetos con ID nulos iguales?