比较c#Complex对象

时间:2015-09-01 09:48:52

标签: c# .net object comparison

我想知道下面的最佳方法

我有一个.NET Web应用程序,我正在更改我正在使用的ORM提供程序。为此,我创建了一个新的解决方案并删除了以前的ORM并实现了我的新解决方案。由于有许多现有的屏幕可以与之前的ORM一起工作,我想确保两个ORMS都返回相同的对象。由于这些是在两个单独的VS slns中,因此有一种简单的方法可以将所有相同属性加载到对象图上的复杂对象进行比较。我可以设置一个断点并手动比较它们但我真的不想这样做吗?

2 个答案:

答案 0 :(得分:0)

如果这是出于测试目的,您可以使用FluentAssertions进行检查。

以下代码声明了两个不相关的类型,ClassAClassB,它们包含两个名为AB的嵌套类,但类型不同。

因此,包含类和嵌套类是不相关的类型,但成员的名称是相同的,对于嵌套类,属性的类型是相同的。

您可以使用FluentAssertions来测试两个实例classAclassB是否相同 - 即使它们的类型不同 - 如下所示:

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

答案 1 :(得分:0)

所以我猜这并不像实现IEquatable接口那么简单,而是使用它来直接比较你的实例。您必须意识到实施正确的比较方法将是最快的方法。

但是有更慢,更灵活的方式。我想你想做的是:

  • 比较两个未知类型的对象
  • 检查它们是否包含具有相同名称的类变量
  • 检查类变量是否具有匹配类型
  • 检查变量中的值是否相同

只有一种方法可以做到这一点。这是问题System.Reflection。请注意,此解决方案将比使用已知类型的所有解决方案慢得多。

所以你需要你的ComplexEquals功能。

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

这是一个简单的版本,它依赖于从未知函数内的第一级开始的Equals函数。这可能就足够了。但我认为这是一个可以在需要时扩展的起点。