使用Reflection比较同结构类时List属性判断异常的问题
问题分析
原代码的核心问题在于:对于引用类型(比如List<T>),默认的Equals方法比较的是对象的引用地址,而非内部内容。哪怕两个List的元素完全一致,只要它们是不同的实例,Equals就会返回false,导致你的函数错误判定为属性值变更,返回true。
修复方案
需要编写递归的比较逻辑,针对不同类型做差异化处理:
- 处理null场景:双null则相等,单null则不等
- 值类型/字符串:直接用
Equals比较 - 集合类型(实现
IEnumerable):逐个元素递归校验 - 自定义引用类型:递归比较其所有属性
修复后的完整代码:
private bool HasPropertyChanges(Class a, Class b) { // 先处理null边界情况 if (a == null && b == null) return false; if (a == null || b == null) return true; var properties = a.GetType().GetProperties(); foreach (var prop in properties) { var valueA = prop.GetValue(a); var valueB = prop.GetValue(b); if (!AreValuesEqual(valueA, valueB)) { return true; // 发现变更直接返回 } } return false; // 所有属性无变更 } private bool AreValuesEqual(object valueA, object valueB) { // 双null判定相等 if (valueA == null && valueB == null) return true; // 单null判定不等 if (valueA == null || valueB == null) return false; var typeA = valueA.GetType(); // 值类型/字符串直接用Equals比较 if (typeA.IsValueType || typeA == typeof(string)) { return valueA.Equals(valueB); } // 集合类型逐个元素递归比较 if (typeof(System.Collections.IEnumerable).IsAssignableFrom(typeA)) { var enumerableA = (System.Collections.IEnumerable)valueA; var enumerableB = (System.Collections.IEnumerable)valueB; var enumeratorA = enumerableA.GetEnumerator(); var enumeratorB = enumerableB.GetEnumerator(); while (true) { bool hasNextA = enumeratorA.MoveNext(); bool hasNextB = enumeratorB.MoveNext(); // 元素数量不同直接不等 if (hasNextA != hasNextB) return false; // 遍历到末尾则集合相等 if (!hasNextA) return true; // 递归比较单个元素 if (!AreValuesEqual(enumeratorA.Current, enumeratorB.Current)) { return false; } } } // 自定义引用类型,递归比较其属性 return !HasPropertyChanges(valueA as dynamic, valueB as dynamic); }
关键说明
- 方法重命名为
HasPropertyChanges,语义更明确 - 新增
AreValuesEqual辅助方法,统一处理不同类型的比较逻辑 - 集合比较会校验元素数量和每个元素的内容,确保List内容一致时判定为相等
- 支持嵌套自定义类的递归比较
- 提前返回逻辑:一旦发现变更立即终止遍历,提升性能
测试验证
针对你给出的示例场景:
- ID、Number等值类型直接比较相等
- List内容完全一致时,
AreValuesEqual会逐个元素校验,返回true,最终函数返回false(无变更) - 当List的元素数量或内容不同时,函数会返回true(存在变更)
内容的提问来源于stack exchange,提问作者sitera
相关产品推荐
相关产品推荐

