2009-06-11 10 views
5

Non sto cercando un confronto tra due strutture che restituiscono bool, mi chiedo se c'è un modo per ottenere quali campi di due strutture (la stessa struttura, ma forse valori diversi) sono diversi. Fondamentalmente voglio un modo più semplice per effettuare le seguenti operazioni:Confronta i valori di due strutture in 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()); 
    } 
} 

Mi chiedo se c'è un modo per fare questo con la serializzazione di qualche tipo, o se questo è l'unico modo per vedere in realtà che i valori sono cambiati . Anche se c'è un modo migliore per implementare la funzione Confronta, lo prenderei anche io.

+0

Controlla la mia soluzione linq. È davvero piccolo. – johnnycrash

risposta

10

Può essere fatto utilizzando Reflection. Cerca gli esempi FieldInfo e PropertyInfo.

MSDN esempio (modificato un po '):

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ì - Risposta corretta – Dario

+0

Esiste un esempio su come ottenere i dati effettivi? Sembra che questo sia solo per i Campi/Proprietà di una classe, o stai solo suggerendo una migliore implementazione per il metodo Confronto? – SwDevMan81

+1

Come hai detto, se vuoi sapere * quali campi * sono diversi, allora devi restituire una sorta di lista (Lista , per esempio). Ma forse potresti descrivere il tuo obiettivo con più dettagli, in modo da poter proporre una soluzione migliore? Ad esempio, se si trattasse di una classe anziché di una struct, si potrebbe considerare l'implementazione dell'interfaccia INotifyPropertyChanged e l'attivazione di un evento ogni volta che una proprietà viene modificata, in questo modo non sarà necessario controllare tutti i campi ogni volta. Tutto dipende dal tuo obiettivo reale. – Groo

1

Non posso aggiungere commenti ancora, in modo in risposta a SwDevMan81 sopra c'è un po'^

Se si desidera che il valore e la si dispone di un FieldInfo ...

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

Inoltre,

GetFields() restituisce variabili membro. I flag controllano se si desidera membri pubblici/privati ​​/ statici, ecc.

GetProperties() restituisce proprietà.

0

Ok, in modo da utilizzare le informazioni per i popoli messaggi, avremmo un nuovo metodo che assomiglia a questo confronto:

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; 
} 

Questo sembra ridurre in modo significativo le dimensioni della funzione di confronto, ma ho ancora tutti la classe Diffs e il codice extra. C'è un modo più semplice di questo ancora?

+0

La tua domanda non è abbastanza specifica per eliminare la classe diffs, poiché la nostra comprensione del risultato che stai cercando è un insieme di tali oggetti. –

+0

La domanda chiede se esiste un modo semplice.Alla fine menziono che mi accontento di una migliore implementazione di Compare se questo è tutto ciò che era possibile – SwDevMan81

+0

Basta aggiungere questo alla tua domanda invece di aggiungere una non risposta. – 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

Purtroppo non posso usare Linq – SwDevMan81