确定实例已覆盖 GetHashCode 和 Equals?
determine that an instance has GetHashCode and Equals overridden?
给定一个 C# 对象实例,我如何确定该对象是否具有值语义?换句话说,我想保证我的 API 中使用的对象适合用作字典键。我在想这样的事情:
var type = instance.GetType();
var d1 = FormatterServices.GetUninitializedObject(type);
var d2 = FormatterServices.GetUninitializedObject(type);
Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode());
您如何看待这种方法?
FormatterServices.GetUninitializedObject
可以使对象处于无效状态;它打破了只读字段等的保证分配。任何假定字段不会 null
的代码都会中断。我不会用那个。
你可以通过反射检查GetHashCode
和Equals
是否被覆盖,但这还不够。您可以覆盖方法调用基础 class 方法。这不算作值语义。
顺便说一句,值语义并不意味着相等的哈希码。也可能是碰撞;值语义意味着具有 equals 属性的两个对象应该 return 相同的 hashcode 以及 equals 方法应该评估为真。
我建议你创建一个实例,分配一些属性,克隆它;现在两个哈希码应该相等并且调用 object.Equals(original, clone)
应该评估为真。
您可以通过以下方式测试 Equals()
和 GetHashCode()
的实现:
s.GetType().GetMethod("GetHashCode").DeclaringType == s.GetType()
或者更确切地说,根据@hvd 的建议:
s.GetType().GetMethod("GetHashCode").DeclaringType != typeof(object)
Some some object,如果GetHashCode()
没有被它的类型实现,这个就是false,否则为true。
需要注意的一件事是,这不会防止 Equals()
或 GetHashCode()
的实施不当 - 即使实施是 public override int GetHashCode() { }
,这也会评估为 true。
考虑到缺点,我倾向于记录您的类型 ("this type should / should not be used for a dictionary key..."),因为这不是您最终可以依赖的东西。如果 Equals()
或 GetHashCode()
的实现有缺陷而不是缺失,它将通过此测试但仍然有 运行 时间错误。
你可以看到一个对象是否定义了它自己的 Equals
和 GetHashCode
使用 DeclaringType
属性 在相应的 MethodInfo
:
bool definesEquality = type.GetMethod("Equals", new[] { typeof(object) }).DelcaringType == type && type.GetMethod("GetHashCode", Type.EmptyTypes).DeclaringType == type;
给定一个 C# 对象实例,我如何确定该对象是否具有值语义?换句话说,我想保证我的 API 中使用的对象适合用作字典键。我在想这样的事情:
var type = instance.GetType();
var d1 = FormatterServices.GetUninitializedObject(type);
var d2 = FormatterServices.GetUninitializedObject(type);
Assert.AreEqual(d1.GetHashCode(), d2.GetHashCode());
您如何看待这种方法?
FormatterServices.GetUninitializedObject
可以使对象处于无效状态;它打破了只读字段等的保证分配。任何假定字段不会 null
的代码都会中断。我不会用那个。
你可以通过反射检查GetHashCode
和Equals
是否被覆盖,但这还不够。您可以覆盖方法调用基础 class 方法。这不算作值语义。
顺便说一句,值语义并不意味着相等的哈希码。也可能是碰撞;值语义意味着具有 equals 属性的两个对象应该 return 相同的 hashcode 以及 equals 方法应该评估为真。
我建议你创建一个实例,分配一些属性,克隆它;现在两个哈希码应该相等并且调用 object.Equals(original, clone)
应该评估为真。
您可以通过以下方式测试 Equals()
和 GetHashCode()
的实现:
s.GetType().GetMethod("GetHashCode").DeclaringType == s.GetType()
或者更确切地说,根据@hvd 的建议:
s.GetType().GetMethod("GetHashCode").DeclaringType != typeof(object)
Some some object,如果GetHashCode()
没有被它的类型实现,这个就是false,否则为true。
需要注意的一件事是,这不会防止 Equals()
或 GetHashCode()
的实施不当 - 即使实施是 public override int GetHashCode() { }
,这也会评估为 true。
考虑到缺点,我倾向于记录您的类型 ("this type should / should not be used for a dictionary key..."),因为这不是您最终可以依赖的东西。如果 Equals()
或 GetHashCode()
的实现有缺陷而不是缺失,它将通过此测试但仍然有 运行 时间错误。
你可以看到一个对象是否定义了它自己的 Equals
和 GetHashCode
使用 DeclaringType
属性 在相应的 MethodInfo
:
bool definesEquality = type.GetMethod("Equals", new[] { typeof(object) }).DelcaringType == type && type.GetMethod("GetHashCode", Type.EmptyTypes).DeclaringType == type;