如何在C#中检查对象是否包含默认值(含嵌套对象场景)
检查对象是否为默认初始化实例(含嵌套对象)
你遇到的问题很典型:直接用==或者Object.ReferenceEquals比较对象和新实例,永远会返回false——因为每次new都会创建一个全新的对象引用,这两个方法本质都是在比较引用是否相同,而不是对象的属性值是否一致。
下面分两种场景给你解决方案:
一、简单对象(无嵌套属性)的情况
方案1:重写Equals和GetHashCode
最直接的方式是在你的类中重写Equals方法,手动比较对象的属性值是否和默认实例一致,同时重写GetHashCode保证哈希值匹配:
public class MyClass { public int Value { get; set; } public MyClass() { this.Value = 10; } // 重写Equals,比较属性值 public override bool Equals(object obj) { // 先判断引用是否相同,或者类型不匹配/为空 if (obj == null || GetType() != obj.GetType()) return false; MyClass other = (MyClass)obj; // 比较所有默认初始化的属性 return Value == other.Value; } // 重写GetHashCode,确保相等的对象哈希值一致 public override int GetHashCode() { return Value.GetHashCode(); } }
之后你就可以这样判断:
if(obj1.Equals(new MyClass())) Console.WriteLine("Initialized with default values");
方案2:重载==运算符
如果你习惯用==语法,还可以重载==和!=运算符,让它直接比较属性值:
public class MyClass { // ... 保留上面的构造函数、Equals和GetHashCode ... public static bool operator ==(MyClass a, MyClass b) { // 先处理引用相同的情况 if (ReferenceEquals(a, b)) return true; // 处理其中一个为空的情况 if (a is null || b is null) return false; // 调用Equals比较属性 return a.Equals(b); } public static bool operator !=(MyClass a, MyClass b) { return !(a == b); } }
现在原来的obj1 == new MyClass()就能正常工作了。
另外,检查对象是否为空直接用obj2 == null就可以,这个是没问题的。
二、包含嵌套对象的场景
如果你的类有嵌套的自定义对象,需要递归比较嵌套对象的属性值,同样可以通过重写Equals实现:
步骤1:给嵌套类重写Equals和GetHashCode
public class MyNestedClass { public string SomeStringProperty { get; set; } public MyNestedClass() { this.SomeStringProperty = "Some string"; } public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) return false; MyNestedClass other = (MyNestedClass)obj; return SomeStringProperty == other.SomeStringProperty; } public override int GetHashCode() { return SomeStringProperty?.GetHashCode() ?? 0; } }
步骤2:在主类的Equals中递归比较嵌套属性
public class MyClass { public int Value { get; set; } public MyNestedClass MyProperty { get; set; } public MyClass() { this.Value = 10; this.MyProperty = new MyNestedClass(); } public override bool Equals(object obj) { if (obj == null || GetType() != obj.GetType()) return false; MyClass other = (MyClass)obj; // 比较自身属性 + 递归比较嵌套对象 return Value == other.Value && Equals(MyProperty, other.MyProperty); } public override int GetHashCode() { // 组合自身和嵌套对象的哈希值 return HashCode.Combine(Value, MyProperty); } }
这样obj1.Equals(new MyClass())就会正确判断所有嵌套属性是否都是默认值了。
通用方案:用反射自动比较所有属性
如果你的项目中有很多类需要做这种检查,手动重写Equals太麻烦,可以写一个通用的反射方法,自动遍历所有属性并比较:
public static bool IsDefaultInstance<T>(T obj) where T : new() { if (obj == null) return false; // 创建一个默认实例作为参照 T defaultInstance = new T(); // 获取所有公共实例属性 var properties = typeof(T).GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance); foreach (var prop in properties) { object objValue = prop.GetValue(obj); object defaultValue = prop.GetValue(defaultInstance); // 如果是自定义类(排除string,因为string是值类型语义),递归检查 if (prop.PropertyType.IsClass && prop.PropertyType != typeof(string)) { if (!IsDefaultInstance(objValue)) return false; } // 值类型或string直接比较 else if (!Equals(objValue, defaultValue)) { return false; } } return true; }
使用方式非常简单:
if (IsDefaultInstance(obj1)) Console.WriteLine("Initialized with default values");
注意:反射会有一定的性能开销,如果是性能敏感的场景(比如高频循环中),还是建议手动重写Equals。
内容的提问来源于stack exchange,提问作者Kunal Mukherjee
相关产品推荐
相关产品推荐

