2009-06-11 31 views
5

No estoy buscando una comparación de dos estructuras que devuelve bool, me pregunto si hay una manera de obtener qué campos de dos estructuras (la misma estructura, pero tal vez valores diferentes) son diferentes. Básicamente quiero una manera más sencilla de hacer lo siguiente:Comparar dos valores de estructuras en C#

public class Diff 
{ 
    public String VarName; 
    public object Val1; 
    public object Val2; 

    public Diff(String varName, object val1, object val2) 
    { 
     VarName = varName; 
     Val1 = val1; 
     Val2 = val2; 
    } 

    public override string ToString() 
    { 
     return VarName + " differs with values " + Val1 + " and " + Val2; 
    } 
} 

public struct TestStruct 
{ 
    public int ValueOne; 
    public int ValueTwo; 
    public int ValueThree; 

    public List Compare(TestStruct inTestStruct) 
    { 
     List diffs = new List(); 
     if (ValueOne != inTestStruct.ValueOne) 
     { 
      diffs.Add(new Diff("ValueOne", ValueOne, inTestStruct.ValueOne)); 
     } 
     if (ValueTwo != inTestStruct.ValueTwo) 
     { 
      diffs.Add(new Diff("ValueTwo", ValueTwo, inTestStruct.ValueTwo)); 
     } 
     if (ValueThree != inTestStruct.ValueThree) 
     { 
      diffs.Add(new Diff("ValueThree", ValueThree, inTestStruct.ValueThree)); 
     } 
     return diffs; 
    } 
} 

public CompareStructsExample() 
{ 
    TestStruct t1 = new TestStruct(); 
    t1.ValueOne = 1; 
    t1.ValueTwo = 8; 
    t1.ValueThree = 5; 

    TestStruct t2 = new TestStruct(); 
    t2.ValueOne = 3; 
    t2.ValueTwo = 8; 
    t2.ValueThree = 7; 

    List diffs = t1.Compare(t2); 
    foreach (Diff d in diffs) 
    { 
     System.Console.WriteLine(d.ToString()); 
    } 
} 

Me pregunto si hay una manera de hacer esto con la serialización de algún tipo, o si esta es la única manera de ver realmente qué valores han cambiado . Incluso si hay una forma mejor de implementar la función Comparar, yo también tomaría eso.

+0

Eche un vistazo a mi solución de linq. Es realmente pequeño – johnnycrash

Respuesta

10

Se puede hacer utilizando Reflection. Verifique los ejemplos FieldInfo y PropertyInfo.

MSDN ejemplo (un poco modificado):

Type myType = typeof(TestStruct); 

    // Get the fields of TestStruct. 
    FieldInfo[] myFieldInfo = 
     myType.GetFields(
      BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public); 

    Console.WriteLine("\nThe fields of TestStruct are \n"); 

    // Display the field information of TestStruct. 
    for(int i = 0; i < myFieldInfo.Length; i++) 
    { 
     Console.WriteLine("\nName   : {0}", myFieldInfo[i].Name); 
     Console.WriteLine("Declaring Type : {0}", myFieldInfo[i].DeclaringType); 
     Console.WriteLine("IsPublic  : {0}", myFieldInfo[i].IsPublic); 
     Console.WriteLine("MemberType  : {0}", myFieldInfo[i].MemberType); 
     Console.WriteLine("FieldType  : {0}", myFieldInfo[i].FieldType); 
     Console.WriteLine("IsFamily  : {0}", myFieldInfo[i].IsFamily); 
    } 
+0

Sí, respuesta correcta – Dario

+0

¿Hay algún ejemplo de cómo obtener los datos reales? Parece que esto es solo para los Campos/Propiedades de una clase, o solo está sugiriendo una mejor implementación para el método Comparar. – SwDevMan81

+1

Como dijiste, si quieres saber * qué * campos son diferentes, entonces necesitas regresar algún tipo de lista (List , por ejemplo). ¿Pero tal vez podría describir su objetivo con más detalle, para que podamos proponer una mejor solución? Por ejemplo, si se tratara de una clase en lugar de struct, podría considerar implementar la interfaz INotifyPropertyChanged y activar un evento cada vez que se cambie una propiedad, de esa manera no tendría que verificar todos los campos cada vez. Todo depende de tu objetivo real. – Groo

1

No puedo añadir comentarios, por lo que en respuesta a SwDevMan81 por encima de allí un poco^

Si desea que el valor y usted tiene un FieldInfo ...

object val = myFieldInfo[i].GetValue(Obj); 

Además,

GetFields() devuelve variables de miembro. Las banderas controlan si quieres miembros públicos/privados/estáticos, etc.

GetProperties() devuelve propiedades.

0

Ok, por lo que el uso de la información de los mensajes de la gente, tendríamos un nuevo método que tiene este aspecto comparar:

public List Compare2(TestStruct inTestStruct) 
{ 
    List diffs = new List(); 

    FieldInfo[] fields = this.GetType().GetFields(); 
    FieldInfo[] fields2 = inTestStruct.GetType().GetFields(); 

    for (int i = 0; i < fields.Length; i++) 
    { 
    object value1 = fields[i].GetValue(this); 
    object value2 = fields2[i].GetValue(inTestStruct); 
    if (!value1.Equals(value2)) 
    { 
     diffs.Add(new Diff(fields[i].Name, value1, value2)); 
    } 
    } 
    return diffs; 
} 

Esto parece reducir significativamente el tamaño de la función de comparación, pero todavía tengo todo la clase Diffs y el código extra. ¿Hay alguna manera más simple que esto todavía?

+0

Su pregunta no es lo suficientemente específica como para deshacerse de la clase diffs, ya que nuestra comprensión del resultado que busca es un conjunto de dichos objetos. –

+0

La pregunta pregunta si hay una manera simple.Al final menciono que me conformaría con una mejor implementación de Compare si eso es todo lo que era posible – SwDevMan81

+0

Simplemente agregue esto a su pregunta en lugar de agregar una no respuesta. – TheSoftwareJedi

0

¿Linq?

public List<string> Compare(TestStruct x, TestStruct y) { 
    return ( 
     from l1 in x.GetType().GetFields() 
     join l2 in y.GetType().GetFields() on l1.Name equals l2.Name 
     where !l1.GetValue(x).Equals(l2.GetValue(y)) 
     select string.Format("{0} {1} {2}", l1.Name, l1.GetValue(x), l2.GetValue(y)) 
    ).ToList(); 
    } 
+0

Desafortunadamente no puedo usar Linq – SwDevMan81