如何判断含自定义类属性的两个对象属性值是否匹配?
对象属性匹配方案的问题与解决
问题背景
正在实现一个判断两个对象是否匹配的方案,规则为:若两个对象拥有同名属性,则属性值需匹配。现有Solution(SC)和Device(DI)两个类,Test属性可正确判定为匹配,但Little类属性因SC和DI使用不同实例,尽管属性值一致仍被判定为不匹配。
代码示例
namespace HelloWorld { using System; using System.Reflection; public class Little { public string L1 { get; set; } public string L2 { get; set; } } public class Solution { public string Name { get; set; } public string Test { get; set; } public Little L {get; set; } } public class Device { public string Name { get; set; } public string Test { get; set; } public Little L {get; set; } } public class Program { static void Main(string[] args) { var Li = new Little { L1 = "L1111", L2 = "L2222" }; var Li2 = new Little { L1 = "L1111", L2 = "L2222" }; var SC = new Solution { Name = "SC", Test = "T1", L = Li2 }; var DI = new Device { Name = "DI", Test = "T1", L = Li }; foreach (var property in SC.GetType().GetProperties()) { var deviceProperty = DI.GetType().GetProperty(property.Name); if (deviceProperty != null) { if (deviceProperty.GetValue(DI) != property.GetValue(SC)) { // 这里会判定不匹配,因为DI和SC的Little是不同实例,但属性值完全一致 // 如何判断属性是否为自定义类(避免将string等引用类型误判)? // 若Little类中嵌套其他类,是否需要递归遍历直到属性为值类型? } else { Console.WriteLine("We have a match"); } } } } } }
疑问
- 如何判断属性是否为自定义类(避免将string等引用类型误判)?
- 若Little类中嵌套其他类,是否需要递归遍历直到属性为值类型?
解决思路
1. 区分自定义类与系统引用类型
要避开string这类系统内置的引用类型,核心是过滤系统类型,可以通过以下逻辑实现:
- 先排除值类型、接口,这些肯定不是自定义类;
- 单独排除string(它是引用类型但属于系统内置);
- 最后检查类型的命名空间是否以
System.开头,自定义类的命名空间一般是你自己定义的(比如示例中的HelloWorld),不会属于System体系。
工具方法代码:
private static bool IsCustomClass(Type type) { if (type.IsValueType || type.IsInterface) return false; if (type == typeof(string)) return false; return !type.Namespace?.StartsWith("System.", StringComparison.OrdinalIgnoreCase) ?? false; }
2. 嵌套类的递归比较
如果自定义类里嵌套了其他自定义类,必须递归遍历比较。只有递归到最底层的值类型、字符串等,才能准确判断属性值是否完全匹配。
可以写一个递归的比较方法,逻辑如下:
- 先处理null情况:都null则匹配,一个null一个非null则不匹配;
- 如果是值类型或string,直接用
Equals比较; - 如果是自定义类,遍历所有属性,递归调用比较方法;
- 其他系统引用类型(如集合、数组)可根据需求扩展处理逻辑。
完整递归比较方法:
private static bool AreObjectsMatching(object obj1, object obj2) { // 处理null情况 if (obj1 == null && obj2 == null) return true; if (obj1 == null || obj2 == null) return false; Type type1 = obj1.GetType(); Type type2 = obj2.GetType(); // 值类型或字符串直接比较 if (type1.IsValueType || type1 == typeof(string)) { return obj1.Equals(obj2); } // 自定义类递归比较属性 if (IsCustomClass(type1)) { foreach (PropertyInfo prop in type1.GetProperties()) { PropertyInfo prop2 = type2.GetProperty(prop.Name); if (prop2 == null) continue; object value1 = prop.GetValue(obj1); object value2 = prop2.GetValue(obj2); if (!AreObjectsMatching(value1, value2)) return false; } return true; } // 其他系统引用类型,默认用Equals判断(可按需扩展) return obj1.Equals(obj2); }
替换原有逻辑
在Main方法中,把原来的直接引用比较替换为递归比较:
foreach (var property in SC.GetType().GetProperties()) { var deviceProperty = DI.GetType().GetProperty(property.Name); if (deviceProperty != null) { object scValue = property.GetValue(SC); object diValue = deviceProperty.GetValue(DI); if (AreObjectsMatching(scValue, diValue)) { Console.WriteLine($"Property {property.Name} matches"); } else { Console.WriteLine($"Property {property.Name} does NOT match"); } } }
这样就能正确判断Little这类自定义类的属性值是否匹配,哪怕是不同实例,只要内部属性值一致就会判定为匹配;如果Little里嵌套了其他自定义类,递归逻辑也能逐层比较。
内容的提问来源于stack exchange,提问作者sarah campolt
相关产品推荐
相关产品推荐

