0

I am wondering about the best approach to the below

I have a .NET Web application and I am changing the ORM provider I am using. To do this I have created a new solution and removed the previous ORM and implemented my new one. As there are lots of existing screens that work with the previous ORM I want to make sure that the same object is returned by both ORMS. As these are in two separate VS slns is there a simple way I can compare the complex objects that all the same properties have been loaded on to the object graph. I could set a breakpoint and compare them manually but I don't really want to do this?

Ctrl_Alt_Defeat
  • 3,933
  • 12
  • 66
  • 116
  • 3
    possible duplicate of [Best way to compare two complex object](http://stackoverflow.com/questions/10454519/best-way-to-compare-two-complex-object) – Alex Sep 01 '15 at 09:53
  • maybe you can use reflection? It won't be fast, but will work – Kamil Budziewski Sep 01 '15 at 09:53
  • perhaps write from the two solutions, serialize them in xml files and then compare the files with a diff tool ? (I undersant you want to run the two solution in // ? is that your question – Cedric Dumont Sep 01 '15 at 09:57
  • 1
    @CedricDumont - correct - I want to run both sln's in parallel - it might be an idea to serialize the entire object to xml and then use winmerge - cheers – Ctrl_Alt_Defeat Sep 01 '15 at 12:12

2 Answers2

0

If this is for testing purposes, you can use FluentAssertions to check this.

The following code declares two unrelated types, ClassA and ClassB which contain two nested classes both called A and B but of different types.

Therefore the containing classes and the nested classes are of unrelated types, but the names of the members are the same, and for the nested classes the types of the properties are the same.

You can use FluentAssertions to test if the two instances classA and classB are equivalent - even though they are of different types - as follows:

using System;
using FluentAssertions;

namespace Demo
{
    class ClassA
    {
        public NestedClassA A;
        public NestedClassB B;
    }

    class NestedClassA
    {
        public string S;
        public int I;
    }

    class NestedClassB
    {
        public char C;
        public double D;
    }

    class ClassB
    {
        public NestedClassC A;
        public NestedClassD B;
    }

    class NestedClassC
    {
        public string S;
        public int I;
    }

    class NestedClassD
    {
        public char C;
        public double D;
    }

    internal class Program
    {
        private static void Main()
        {
            var nestedA = new NestedClassA {I = 1, S = "1"};
            var nestedB = new NestedClassB {C = '1', D = 1};

            var nestedC = new NestedClassC { I = 1, S = "1" };
            var nestedD = new NestedClassD { C = '1', D = 1 };

            var classA = new ClassA {A = nestedA, B = nestedB};
            var classB = new ClassB {A = nestedC, B = nestedD};

            classA.ShouldBeEquivalentTo(classB); // Passes
            classB.ShouldBeEquivalentTo(classA); // Passes

            classB.B.D = 2; // Now the two objects do not contain equivalent data.

            classA.ShouldBeEquivalentTo(classB); // Fails.
        }
    }
}
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
0

So I am guessing it is not as simple as to implement the IEquatable interface and directly compare your instances using this. You have to be aware that implementing proper comparing methods will be the fastest way.

But there are slower, more flexible ways. I think what you want to do is:

  • Compare two objects of unknown types
  • Check if they contain class variables with the same name
  • Check if the class variables have matching types
  • Check if the values in the variables are the same

There is only one way to do that. And it is to throw System.Reflection at the problem. Mind that this solution will be considerably slower then all solutions that work with known types.

So you need your ComplexEquals function.

public static bool ComplexEquals(object obj1, object obj2)
{
  if (obj1 == null && obj2 == null) return true;
  if (obj1 == null || obj2 == null) return false;

  var obj1Class = obj1.GetType();
  var obj2Class = obj2.GetType();

  /* Get the instance fields (all of them) of both classes. */
  var obj1Fields = obj1Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);
  var obj2Fields = obj2Class.GetFields(System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public);

  var checkedFields = new HashSet<String>();

  foreach (var obj1Field in obj1Fields)
  {
    var fieldName = obj1Field.Name;
    checkedFields.Add(fieldName);
    var obj2Field = obj2Fields.Where(f => f.Name == fieldName).SingleOrDefault();
    if (obj2Field == null) return false;
    if (obj1Field.FieldType == obj2Field.FieldType && !(obj1Field.GetValue(obj1).Equals(obj2Field.GetValue(obj2)))) return false;
  }

  if (obj2Fields.Any(f => !checkedFields.Contains(f.Name))) return false;
  return true;
}

This is a simple version that relies on the Equals function starting at the first level inside the unknown function. This may be sufficient or not. But I think that is a starting point that can be extended if required.

Nitram
  • 6,486
  • 2
  • 21
  • 32