views:

771

answers:

5

I'm not looking for a comparison of two structs that returns bool, I am wondering if there is a way to get which fields of two structs (the same structure, but maybe different values) are different. Basically I want a simpler way to do the following:


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

I'm wondering if there is a way to do this with serialization of some sort, or if this is the only way to actually see which values have changed. Even if there is a better way to implement the Compare function, I would take that too.

A: 

In C/++ it may be possible to turn it into a char* buffer and somehow check which values changed, but I don't know how you'd go about this in C#.

Saul Rennison
That isn't helpful.
Dario
+10  A: 

It can be done using Reflection. Check for FieldInfo and PropertyInfo examples.

MSDN example (modified a bit):

    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);
    }
Groo
Yep - Correct answer
Dario
Is there an example on how to get the actual data? Looks like this is just for the Fields/Properties of a class, or are you just suggesting a better implementation for the Compare method?
SwDevMan81
As you said, if you want to know *which* fields are different, then you need to return some sort of a list (List<Diff>, for example). But maybe you could describe your goal with more detail, in order for us to propose a better solution?For example, if this was a class instead of struct, you could consider implementing the INotifyPropertyChanged interface and firing an event whenever a property is changed - that way you wouldn't have to check all fields each time. It all depends on your actual goal.
Groo
@Groo - The ultimate goal is to compare two XML files and display the attributes and values that are different. I figured the XML file would be serialized into the structure and parsed for differences. I wont need to know (INotifyPropertyChanged) if the value of the structures change.
SwDevMan81
+1  A: 

I can't add comments yet, so in response to SwDevMan81 up above there a bit ^

If you want the value and you have a FieldInfo...

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

Also,

GetFields() returns member variables. The flags control if you want public/private/static etc members.

GetProperties() returns properties.

johnnycrash
A: 
SwDevMan81
Your question is not specific enough to get rid of the diffs class, as our understanding of the result your looking for is a set of such objects.
Frank Schwieterman
The question asks if there is a simpilar way. At the end I mention I would settle for a better implementation of Compare if thats all that was possible
SwDevMan81
Just add this to your question instead of adding a non-answer.
TheSoftwareJedi
@TheSoftwareJedi - What if this is the answer? I can move it to the question if there is something better, you have any actual input on the question?
SwDevMan81
A: 

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();  
  }
johnnycrash
Unfortunately I cant use Linq
SwDevMan81