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

如何解决c#对象与复杂对象的比较

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

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

我的问题是,有时将一个对象传递给它,其中可能包含其他对象的列表。因为它仅在顶级进行比较,所以它仅返回对象数组已更改的信息。理想情况下,我希望它遍历嵌套数组并查看更改后的值。

理想情况下,我认为它在找到对象数组时可能应该进行递归调用。有什么想法可以解决吗?

编辑-带有工作示例

下面是一些.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已从“ 5”更改为“ 4”

如果我添加:

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

在“收集”检查中,我收到一条错误消息:

对象不包含'DetailedCompare'的定义...无法将实例参数类型'对象'转换为T

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

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

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

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

解决方法

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

如果我们调用方法DetailedCompare来递归地将两个对象作为参数传递,因为我们可以获取它们的属性并进行比较。

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

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

这是我编写的扩展类

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

具有以下结果: enter image description here

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

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-