c#对象与复杂对象的比较

c#对象与复杂对象的比较,c#,comparison,C#,Comparison,我有一个通用的对象比较方法,用于比较具有相同结构的两个模型 public static List<Variance> DetailedCompare<T>(this T val1, T val2) { var variances = new List<Variance>(); var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instan

我有一个通用的对象比较方法,用于比较具有相同结构的两个模型

public static List<Variance> DetailedCompare<T>(this T val1, T val2)
  {
    var variances = new List<Variance>();

    var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
    foreach (var property in properties.Where(t => t.IsMarkedWith<IncludeInComparisonAttribute>()))
      {
        var v = new Variance
          {
            PropertyName = property.Name,
            ValA = property.GetValue(val1, null),
            ValB = property.GetValue(val2, null)
          };

          if (v.ValA == null && v.ValB == null) { continue; }

          if (v.ValA != null && !v.ValA.Equals(v.ValB))
            {
              variances.Add(v);
            }
          }
        return variances;
    }
递归调用似乎不起作用

正如我刚刚得到的:

我找到了一个嵌套列表 属性:NumberOfDesks已从“5”更改为“4”

如果我加上:

var list = v.ValA.DetailedCompare<T>(v.ValB);
var list=v.ValA.DetailedCompare(v.ValB);
在集合检查中,我得到一个错误:

对象不包含“DetailedCompare”的定义。。。无法将实例参数类型“object”转换为T

实际上,我想从中得到的只是一个包含所有属性名及其值更改的数组

属性:NumberOfDesks已从“5”更改为“4”

属性:Id已从“1”更改为“4”

属性:名字已从“柴郡”更改为“门”


etc

递归调用方法是这里的问题

如果我们调用一个方法
DetailedCompare
递归地将两个对象作为参数传递,这一切都很好,因为我们可以得到它们的属性并对它们进行比较

然而,当我们递归地调用
DetailedCompare
传递两个对象列表时,我们不能只获取这些列表的属性,我们需要遍历并获取这些列表的属性,并比较它们的值

IMHO最好使用helper方法来分离逻辑,这样当我们找到一个嵌套列表时,我们就可以像我上面描述的那样处理逻辑了

这是我写的扩展类

  public static class Extension
    {
        public static List<Variance> Variances { get; set; }

        static Extension()
        {
            Variances = new List<Variance>();
        }

        public static List<Variance> DetailedCompare<T>(this T val1, T val2)
        {
            var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var v = new Variance
                {
                    PropertyName = property.Name,
                    ValA = property.GetValue(val1, null),
                    ValB = property.GetValue(val2, null)
                };

                if (v.ValA == null && v.ValB == null)
                {
                    continue;
                }

                if (v.ValA is ICollection)
                {
                    Console.WriteLine("I found a nested list");
                    DetailedCompareList(v.ValA,v.ValB);
                }
                else if (v.ValA != null && !v.ValA.Equals(v.ValB))
                {
                    Variances.Add(v);
                }
            }

            return Variances;
        }

        private static void DetailedCompareList<T>(T val1, T val2)
        {
            if (val1 is ICollection collection1 && val2 is ICollection collection2)
            {
                var coll1 = collection1.Cast<object>().ToList();
                var coll2 = collection2.Cast<object>().ToList();

                for (int j = 0; j < coll1.Count; j++)
                {
                    Type type = coll1[j].GetType();
                    PropertyInfo[] propertiesOfCollection1 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                    PropertyInfo[] propertiesOfCollection2 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

                    for (int i = 0; i < propertiesOfCollection1.Length; i++)
                    {
                        var variance = new Variance
                        {
                            PropertyName = propertiesOfCollection1[i].Name,
                            ValA = propertiesOfCollection1[i].GetValue(coll1[j]),
                            ValB = propertiesOfCollection2[i].GetValue(coll2[j])
                        };

                        if (!variance.ValA.Equals(variance.ValB))
                        {
                            Variances.Add(variance);
                        }
                    }
                }
            }
        }
    }
公共静态类扩展
{
公共静态列表变量{get;set;}
静态扩展()
{
差异=新列表();
}
公共静态列表DetailedCompare(此T值1,T值2)
{
var properties=typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
foreach(属性中的var属性)
{
var v=新方差
{
PropertyName=property.Name,
ValA=property.GetValue(val1,null),
ValB=property.GetValue(val2,null)
};
if(v.ValA==null&&v.ValB==null)
{
继续;
}
如果(v.ValA是ICollection)
{
WriteLine(“我发现了一个嵌套列表”);
详细比较列表(v.ValA,v.ValB);
}
else如果(v.ValA!=null&!v.ValA.Equals(v.ValB))
{
差异。添加(v);
}
}
回报差异;
}
私有静态无效详细比较列表(T值1,T值2)
{
if(val1是ICollection collection1&&val2是ICollection collection2)
{
var coll1=collection1.Cast().ToList();
var coll2=collection2.Cast().ToList();
对于(int j=0;j
结果如下:

限制
这种方法受对象定义的限制,因此只能在1级深度下使用。

挑战在于为嵌套对象存储这些差异。因为他们会在。。或者你想让一个变量包含所有级别的方差吗?我想你不想这样做,不如把顶层的方差设置成字典,其他底层的变量用它们的键存储。。。e、 g
dictionary[“level1”]或dictionary[“level2”]
等。。。您会感激吗?您必须小心引用类型(字符串除外)的相等性比较,这样可能会得到不想要的结果。可能您正在覆盖所有自定义类的相等,否则具有相同值的两个不同实例将不相等。谢谢。我很高兴单变量数组中的所有差异你已经回答了你的问题,你需要递归。如果(ValA是IEnumerable eA&&ValB是IEnumerable eB)
并执行一些自定义逻辑,在其中迭代并调用
DetailCompare
。然后,您只需要为
DetailCompare
创建一个重载,该重载采用
类型,而不是
太好了,谢谢。看起来它能完成任务。在我的代码中,v.Valb作为哈希集出现。你知道我该怎么处理吗?if中的casting DetailedCompareList在itI上不起作用,我更改了代码以检查它是否为IEnumerable且是否起作用。谢谢你的帮助。if(val1是IEnumerable collection1&&val2是IEnumerable collection2)
  public static class Extension
    {
        public static List<Variance> Variances { get; set; }

        static Extension()
        {
            Variances = new List<Variance>();
        }

        public static List<Variance> DetailedCompare<T>(this T val1, T val2)
        {
            var properties = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var property in properties)
            {
                var v = new Variance
                {
                    PropertyName = property.Name,
                    ValA = property.GetValue(val1, null),
                    ValB = property.GetValue(val2, null)
                };

                if (v.ValA == null && v.ValB == null)
                {
                    continue;
                }

                if (v.ValA is ICollection)
                {
                    Console.WriteLine("I found a nested list");
                    DetailedCompareList(v.ValA,v.ValB);
                }
                else if (v.ValA != null && !v.ValA.Equals(v.ValB))
                {
                    Variances.Add(v);
                }
            }

            return Variances;
        }

        private static void DetailedCompareList<T>(T val1, T val2)
        {
            if (val1 is ICollection collection1 && val2 is ICollection collection2)
            {
                var coll1 = collection1.Cast<object>().ToList();
                var coll2 = collection2.Cast<object>().ToList();

                for (int j = 0; j < coll1.Count; j++)
                {
                    Type type = coll1[j].GetType();
                    PropertyInfo[] propertiesOfCollection1 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);
                    PropertyInfo[] propertiesOfCollection2 = type.GetProperties(BindingFlags.Public | BindingFlags.Instance);

                    for (int i = 0; i < propertiesOfCollection1.Length; i++)
                    {
                        var variance = new Variance
                        {
                            PropertyName = propertiesOfCollection1[i].Name,
                            ValA = propertiesOfCollection1[i].GetValue(coll1[j]),
                            ValB = propertiesOfCollection2[i].GetValue(coll2[j])
                        };

                        if (!variance.ValA.Equals(variance.ValB))
                        {
                            Variances.Add(variance);
                        }
                    }
                }
            }
        }
    }