2009-04-28 18 views
6

Necesito escribir un método genérico en la clase base que acepte 2 objetos como parámetros y los compare por igualdad.Comparando 2 objetos personalizados - C#

Ex:

public abstract class BaseData 
{ 

    public bool AreEqual(object O1, object O2) 
    { 
    //Need to implement this 
    } 
} 

public class DataTypeOne : BaseData 
{ 
    public string Name; 
    public string Address; 
} 

public class DataTypeTwo : BaseData 
{ 
    public int CustId; 
    public string CustName; 
} 

El método AreEqual() aceptaría 2 casos de DataTypeOne o 2 casos de DataTypeTwo.

Supongo que necesito usar Reflection? Puedo usar LINQ si puede ser más legible/conciso.

EDIT: La razón por la que me gustaría implementar este método en la clase base es debido a las restricciones del proyecto. Hay una gran cantidad de desarrolladores que trabajan en las clases derivadas. Al implementar esto en la clase base, estoy tratando de tener 1 cosa menos de la que preocuparse.

+0

¿Por qué no se reemplaza Object.equals? – Paco

+0

¿Por qué necesita implementar AreEqual en la clase base (y por qué sin genéricos)? Si AreEqual es abstracto y DataTypeOne y DataTypeTwo implementa AreEqual, esta es una solución más limpia. En resumen: ¿cuál es el motivo del método AreEqual común? – boj

Respuesta

13

(Suponiendo que lo que quiere es comparar todos los campos de los dos objetos son iguales.)

Por lo general, no se molestaría utilizando la reflexión para esto, usted acaba de comparar cada práctica de ejercicio. La interfaz IEquatable<T> existe para este fin, y también es posible que desee sobrescribir Object.Equals() en los tipos en cuestión. Por ejemplo:

public class DataTypeTwo : BaseData, IEquatable<DataTypeTwo> 
{ 
    public int CustId; 
    public string CustName; 

    public override int GetHashCode() 
    { 
     return CustId^CustName.GetHashCode(); // or whatever 
    } 

    public override bool Equals(object other) 
    { 
     return this.Equals(other as DataTypeTwo); 
    } 

    public bool Equals(DataTypeTwo other) 
    { 
     return (other != null && 
       other.CustId == this.CustId && 
       other.CustName == this.CustName); 
    } 
} 

Además, considere si o no su tipo tiene sentido como struct lugar. Los tipos de valor comparan automáticamente la igualdad haciendo una comparación de campo por campo.

Tenga en cuenta que al anular Equals, básicamente logrará lo que (me parece a mí) está tratando de lograr con su esquema "master equals method". Es decir, las personas que usan DataTypeTwo podrán probar de forma natural la igualdad sin tener que saber nada especial sobre su API; solo usarán Equals como lo harían con otras cosas.

EDITAR: Gracias a Jared por recordarme acerca de GetHashCode. También querrás anularlo para mantener el comportamiento de aspecto normal en hashtables asegurándote de que dos objetos que son "iguales" también devuelvan el mismo código hash.

+1

Todavía es necesario reemplazar GetHashCode ot – JaredPar

+0

Por qué necesita GetHashCode, es igual no es suficiente? –

+1

Por favor, nunca cambie una clase a una estructura por el solo hecho de cambiar el comportamiento de comparación de Igualdad. Los pequeños tipos de datos como las coordenadas cartesianas que se espera que se comporten de una determinada manera "por valor" están bien; pero las estructuras de datos que otro programador asumirá que son de una clase no deberían convertirse en estructuras para comparar por valor; también cambiarás invisiblemente el comportamiento wrt. inicialización y (lo más importante) asignación. – perfectionist

0

Sí, tendrá que usar la reflexión, porque la clase base no sabe nada sobre las clases derivadas. Pero, ¿por qué quieres implementar esa función en la clase base? ¿Por qué no en las clases derivadas?

Además, hay una forma estándar de hacerlo anulando Object.GetHashCode() y Object.Equals().

1

que probablemente hacer algo como esto:

public abstract class BaseData : IEquatable<BaseData> 
{ 
    public abstract bool Equals(BaseData other); 
} 

public class DataTypeOne : BaseData 
{ 
    public string Name; 
    public string Address; 

    public override bool Equals(BaseData other) 
    { 
     var o = other as DataTypeOne; 
     if(o == null) 
      return false; 
     return Name.Equals(o.Name) && Address.Equals(o.Address); 
    } 
} 

public class DataTypeTwo : BaseData 
{ 
    public int CustId; 
    public string CustName; 

    public override bool Equals(BaseData other) 
    { 
     var o = other as DataTypeTwo; 
     if (o == null) 
      return false; 
     return CustId == o.CustId && CustName.Equals(o.CustName); 
    } 
} 
+0

Quizás una explicación de por qué es "loco" sería agradable. – madcolor

+0

Bueno, yo sólo creo que realmente no hay necesidad de comparar DataTypeOne y DataTypeTwo, ya que nunca serán iguales. En otras palabras que probablemente simplemente aplicar IEquatable en DataTypeOne y/o IEquatable en DataTypeTwo. O más probable es que me acaba de utilizar LINQ o algo para decir, buscar un DataTypeTwo particlar con un ID de cliente particular, por ejemplo, y se molestó con el IEquatable o anulación es igual o algo por el estilo. – Svish

4

Esto es lo que ocurrió con el uso de la reflexión. Espero eso ayude.

public bool AreEqual(object obj) 
    { 
     bool returnVal = true; 

     if (this.GetType() == obj.GetType()) 
     { 
      FieldInfo[] fields = this.GetType().GetFields(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public); 

      foreach (FieldInfo field in fields) 
      { 
       if(field.GetValue(this) != field.GetValue(obj)) 
       { 
        returnVal = false; 
        break; 
       } 
      } 
     } 
     else 
      returnVal = false; 

     return returnVal; 
    } 
+0

Gracias Crispy, eso fue * exactamente * lo que estaba buscando! – Lanceomagnifico

2

Do not do it. La herencia es el camino a seguir y cada clase debe anular Equal y GetHashCode cuando sea necesario.

Tal vez obtenga algo de trabajo de esos desarrolladores ahora, pero volveré a morderlo en el futuro cuando se necesite mantener el producto .

serio, sólo tratar de encontrar otra manera de ayudar.

+1

+1, a veces la única respuesta correcta a "¿Cómo?" es "No hacer". – jwg

0
public void CompareTwoObjects() 
{ 
    try { 
     byte[] btArray = ObjectToByteArray(object1); //object1 is you custom object1 
     byte[] btArray2 = ObjectToByteArray(object2); //object2 is you custom object2 
     bool result = ByteArrayCompare(btArray, btArray2); 
    } catch (Exception ex) { 
     throw ex; 
    } 
} 

public byte[] ObjectToByteArray(object _Object) 
{ 
    try { 
     // create new memory stream 
     System.IO.MemoryStream _MemoryStream = new System.IO.MemoryStream(); 

     // create new BinaryFormatter 
     System.Runtime.Serialization.Formatters.Binary.BinaryFormatter _BinaryFormatter 
      = new System.Runtime.Serialization.Formatters.Binary.BinaryFormatter(); 

     // Serializes an object, or graph of connected objects, to the given stream. 
     _BinaryFormatter.Serialize(_MemoryStream, _Object); 

     // convert stream to byte array and return 
     return _MemoryStream.ToArray(); 
    } catch (Exception _Exception) { 
     // Error 
     Console.WriteLine("Exception caught in process: {0}", _Exception.ToString()); 
    } 

    // Error occured, return null 
    return null; 
} 

public bool ByteArrayCompare(byte[] a1, byte[] a2) 
{ 
    if (a1.Length != a2.Length) 
     return false; 

    for (int i = 0; i < a1.Length; i++) 
     if (a1[i] != a2[i]) 
      return false; 

    return true; 
} 
+1

¡Gracias por publicar una respuesta! Si bien un fragmento de código podría responder a la pregunta, sigue siendo genial agregar información adicional, como explicar, etc. – j0k

Cuestiones relacionadas