如何比较两个不同复杂类型的列表?解决多属性匹配及报错问题
不同复杂类型列表的属性批量比较方案
场景与需求
现有两个不同复杂类型的C#列表,需要比较两个列表中对应元素的所有属性,获取每个属性的匹配结果(true或false)。由于列表对应的类包含100+属性,需要一种可扩展、无需逐个编写比较逻辑的方案。
示例代码
列表初始化
List<Test> t1 = new List<Test>() { new Test("TestName", "MyProperty", 50), new Test("TestName2", "MyProperty2", 50) }; List<Test2> t2 = new List<Test2>() { new Test2 { NameT2 = "TestName", PropertyT2 = "MyProperty", ValueT3 = 50 }, new Test2 { NameT2 = "Hector", PropertyT2 = "MyProperties", ValueT3 = 60 } };
类定义
public class Test { public Test(string name, string property, int value) { Name = name; Property = property; Value = value; } public string Name { get; set; } public string Property { get; set; } public int Value { get; set; } } public class Test2 { public string NameT2 { get; set; } public string PropertyT2 { get; set; } public int ValueT3 { get; set; } public int AdditionalT4 { get; set; } }
遇到的问题
之前尝试的两种方案均存在缺陷:
- 手动编写Linq比较逻辑:由于属性数量超过100个,逐个编写比较代码工作量极大,且后续属性变更时维护成本高。
- 自定义
DynamicComparer结合Intersect:因两个类的属性名不匹配(如Test的Name对应Test2的NameT2),运行时抛出异常:'IdaTransaction.POC.DotNetApps.Model.DataModel.Test2' 不包含 'Name' 的定义。该Comparer代码如下:
public class DynamicComparer : IEqualityComparer<object> { public bool Equals(dynamic x, dynamic y) { return x.Name == y.Name && x.Age == y.Age; } public int GetHashCode(dynamic obj) { return ((string)obj.Name).GetHashCode() * 31 + ((int)obj.Age).GetHashCode(); } }
可行解决方案
通过反射+属性映射的方式实现动态批量比较,具体步骤如下:
1. 定义属性映射关系
创建字典存储两个类的属性对应关系,解决属性名不一致的问题:
var propertyMap = new Dictionary<string, string> { { nameof(Test.Name), nameof(Test2.NameT2) }, { nameof(Test.Property), nameof(Test2.PropertyT2) }, { nameof(Test.Value), nameof(Test2.ValueT3) } };
2. 封装通用比较方法
利用反射动态获取属性并比较值,返回每个属性的匹配结果列表:
using System.Reflection; public static Dictionary<string, List<bool>> CompareLists<T1, T2>(List<T1> list1, List<T2> list2, Dictionary<string, string> propertyMapping) { var comparisonResults = new Dictionary<string, List<bool>>(); Type type1 = typeof(T1); Type type2 = typeof(T2); // 获取T1的所有公共实例属性 PropertyInfo[] properties1 = type1.GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (PropertyInfo prop1 in properties1) { // 查找T2中对应的属性名 if (propertyMapping.TryGetValue(prop1.Name, out string prop2Name)) { PropertyInfo? prop2 = type2.GetProperty(prop2Name, BindingFlags.Public | BindingFlags.Instance); if (prop2 == null) continue; List<bool> propertyMatchResults = new List<bool>(); int maxIndex = Math.Min(list1.Count, list2.Count); // 遍历两个列表的对应元素,比较属性值 for (int i = 0; i < maxIndex; i++) { object? value1 = prop1.GetValue(list1[i]); object? value2 = prop2.GetValue(list2[i]); // 处理null值的比较 bool isEqual = value1 == null ? value2 == null : value1.Equals(value2); propertyMatchResults.Add(isEqual); } comparisonResults.Add(prop1.Name, propertyMatchResults); } } return comparisonResults; }
3. 使用示例
调用比较方法并输出结果:
var result = CompareLists(t1, t2, propertyMap); // 打印每个属性的匹配结果 foreach (var kvp in result) { Console.WriteLine($"属性 {kvp.Key} 的匹配结果:"); foreach (bool match in kvp.Value) { Console.WriteLine($"\t{match}"); } }
方案优势
- 适配大量属性:无需逐个编写比较逻辑,只需维护属性映射字典即可。
- 灵活扩展:新增或修改属性时,仅需更新映射字典,无需修改核心比较逻辑。
- 处理属性名差异:通过映射字典解决不同类之间属性名不匹配的问题。
- 空值兼容:自动处理属性值为
null的情况,避免空引用异常。
内容的提问来源于stack exchange,提问作者Subashree Krishnan
相关产品推荐
相关产品推荐

