繁体   English   中英

c# Object 与复杂对象的比较

[英]c# Object Comparison With Complex Objects

我有一个通用的 object 比较方法,我用它来比较具有相同结构的两个模型。

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

我遇到的问题是,有时将 object 传递给它,其中可能包含其他对象的列表。 因为它只在顶层进行比较,所以它只返回 object 数组已更改。 理想情况下,我希望它通过嵌套数组 go 并查看更改的值。

理想情况下,我认为它应该在找到 object 数组时进行递归调用。 任何想法我怎么可能 go 关于这个?

编辑 - 带有工作示例

这是一些 .net 小提琴示例,说明这是如何工作的。

这是第一个不向下搜索嵌套对象并仅报告集合已更改的代码示例(根据上面的代码):

https://dotnetfiddle.net/Cng7GI

返回:

属性:NumberOfDesks 已从“5”更改为“4”属性:学生已从“System.Collections.Generic.List 1[Student]' to 'System.Collections.Generic.List 1[Student]”

现在,如果我使用以下方法找到嵌套数组,则尝试调用DetailedCompare:

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

看起来递归调用不起作用

https://dotnetfiddle.net/Ns1tx5

正如我刚刚得到的:

我找到了一个嵌套列表属性:NumberOfDesks has changed from '5' to '4'

如果我添加:

var list = v.ValA.DetailedCompare<T>(v.ValB);

在集合检查中,我收到一个错误:

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

我真正想要的只是所有属性名称及其值更改的单个数组。

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

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

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

ETC

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

如果我们调用DetailedCompare方法递归地传递两个对象作为参数,一切都很好——因为我们可以获取它们的属性并比较它们。

然而,当我们以递归方式调用DetailedCompare并传递两个对象列表时——我们不仅可以获取这些列表的属性——还需要遍历并获取这些列表的属性并比较它们的值。

恕我直言,最好使用辅助方法来分离逻辑 - 所以当我们找到一个嵌套列表时 - 我们可以处理我上面描述的逻辑。

这是我写的扩展 class

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

结果如下: 在此处输入图像描述

限制这种方法受对象定义的限制——因此它只能在 1 级深度下工作。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM