2011-01-24 19 views
7

así que estoy tratando de hacer este trabajo y me parece que no puede saber por qué no funcionaLINQ y distinta, la aplicación de los iguales y GetHashCode

código de demostración;

namespace ConsoleApplication1 
{ 
class Program 
{ 
    static void Main(string[] args) 
    { 
     var myVar = new List<parent >(); 
     myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } }); 
     myVar.Add(new parent() { id = "id1", blah1 = "blah1", c1 = new child() { blah2 = "blah2", blah3 = "blah3" } }); 

     var test = myVar.Distinct(); 

     Console.ReadKey(); 

    } 
} 


public class parent : IEquatable<parent> 
{ 
    public String id { get;set;} 
    public String blah1 { get; set; } 
    public child c1 { get; set; } 

    public override int GetHashCode() 
    { 
     unchecked // Overflow is fine, just wrap 
     { 
      int hash = 17; 
      // Suitable nullity checks etc, of course :) 
      hash = hash * 23 + id.GetHashCode(); 
      hash = hash * 23 + blah1.GetHashCode(); 
      hash = hash * 23 + (c1 == null ? 0 : c1.GetHashCode()); 
      return hash; 
     } 
    } 

    public bool Equals(parent other) 
    { 
     return object.Equals(id, other.id) && 
      object.Equals(blah1, other.blah1) && 
      object.Equals(c1, other.c1); 
    } 

} 

public class child : IEquatable<child> 
{ 
    public String blah2 { get; set; } 
    public String blah3 { get; set; } 

    public override int GetHashCode() 
    { 
     unchecked // Overflow is fine, just wrap 
     { 
      int hash = 17; 
      // Suitable nullity checks etc, of course :) 
      hash = hash * 23 + blah2.GetHashCode(); 
      hash = hash * 23 + blah3.GetHashCode(); 
      return hash; 
     } 
    } 

    public bool Equals(child other) 
    { 
     return object.Equals(blah2, other.blah2) && 
      object.Equals(blah3, other.blah3); 
    } 

} 
} 

Nadie podría detectar mi error (s)?

+4

+1 para obtener un ejemplo completo. – SLaks

+1

¿Qué error estás recibiendo? ¿Cuál es el comportamiento previsto? Ejecutar su código simplemente no muestra nada y sale cuando se presiona una tecla. – jdmichal

+0

@jdmichal, pon un punto de interrupción en la consola.readkey y mira la variable de prueba, debería decir count = 1 not 2 – Fredou

Respuesta

5

se debe redefinir el método Equals(object):

public override bool Equals(object obj) { 
    return Equals(obj as parent); 
} 

El método object.Equals (a diferencia de EqualityComparer<T>.Default) no utiliza la interfaz IEquatable. Por lo tanto, cuando escribe object.Equals(c1, other.c1), no llama a su método Child.Equals(Child).

No es necesario que haga eso también para parent, pero realmente debería.

+0

Error 'ConsoleApplication1.parent. Equals (ConsoleApplication1.parent) ': no ​​se encontró ningún método adecuado para anular – Fredou

+0

@Fredou: Olvidé agregar el tipo de devolución. – SLaks

+0

esto necesitaría suponer que c1! = Null y EqualityComparer no le importaría, ¿verdad? – Fredou

0

Al agregar el cálculo del hash es posible que desee intentar algo así como

hash ^= id.GetHashCode();

No estoy seguro si eso es lo que está causando el problema.

+0

Creo que su hash está bien, y en todo caso, si fue malo conduciría a un rendimiento pobre, no a un resultado incorrecto (siempre que el hash sea determinista, lo que es claramente en este caso). Y el problema de perforación ciertamente no sería notable con solo 2 artículos. :) –

3

O haces lo que sugiere SLaks, o utiliza EqualityComparer<child>.Default en su clase parent utilizar su aplicación IEquatable<child>:

public bool Equals(parent other) 
    { 
    return object.Equals(id, other.id) && 
    object.Equals(blah1, other.blah1) && 
    EqualityComparer<child>.Default.Equals(c1, other.c1); 
} 
+0

este trabajo, ahora necesito saber cuál es la mejor práctica, implementando esto o SLaks forma – Fredou

+1

Usted ** realmente ** debe anular 'Igual (objeto)'. De lo contrario, es probable que obtenga otras sorpresas desagradables. – SLaks

+0

debe anular Igual (objeto): De acuerdo. – ulrichb

0

Hay varias cosas para conseguir aquí. Si voy a implementar cualquier aspecto de igualdad en una clase como GetHashCode, reemplazando == o IEquatable, siempre uso el siguiente patrón.

  1. sobrescribir equals
  2. GetHashCode Anulación
  3. Implementar IEquatable<T> que significa la implementación de Equals(T)
  4. Implementar! =
  5. Implementar ==

Por lo tanto, si tuviera una clase llamada con ExpiryMonth Propiedades Año y Mes, así es como se vería la implementación. Ahora es una tarea bastante estúpida adaptarse a otros tipos de clases.

He basado este patrón en varias otras respuestas de stackoverflow que merecen todo el crédito, pero que no he rastreado en el camino.

Al implementar todos estos elementos juntos, garantiza operaciones de igualdad adecuadas en una variedad de contextos, incluidos diccionarios y operaciones Linq.

public static bool operator !=(ExpiryMonth em1, ExpiryMonth em2) 
    { 
     if (((object)em1) == null || ((object)em2) == null) 
     { 
      return !Object.Equals(em1, em2); 
     } 
     else 
     { 
      return !(em1.Equals(em2)); 
     } 
    } 
    public static bool operator ==(ExpiryMonth em1, ExpiryMonth em2) 
    { 
     if (((object)em1) == null || ((object)em2) == null) 
     { 
      return Object.Equals(em1, em2); 
     } 
     else 
     { 
      return em1.Equals(em2); 
     } 
    } 
    public bool Equals(ExpiryMonth other) 
    { 
     if (other == null) { return false; } 
     return Year == other.Year && Month == other.Month; 
    } 
    public override bool Equals(object obj) 
    { 
     if (obj == null) { return false; } 
     ExpiryMonth em = obj as ExpiryMonth; 
     if (em == null) { return false; } 
     else { return Equals(em); } 
    } 
    public override int GetHashCode() 
    { 
     unchecked // Overflow is not a problem 
     { 
      var result = 17; 
      result = (result * 397) + Year.GetHashCode(); 
      result = (result * 397) + Month.GetHashCode(); 
      return result; 
     } 
    } 
Cuestiones relacionadas