Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/powershell/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 确定实例已覆盖GetHashCode和Equals?_C#_.net_Equality - Fatal编程技术网

C# 确定实例已覆盖GetHashCode和Equals?

C# 确定实例已覆盖GetHashCode和Equals?,c#,.net,equality,C#,.net,Equality,给定C#中对象的实例,如何确定该对象是否具有值语义?换句话说,我想保证API中使用的对象适合用作字典键。我在想这样的事情: var type = instance.GetType(); var d1 = FormatterServices.GetUninitializedObject(type); var d2 = FormatterServices.GetUninitializedObject(type); Assert.AreEqual(d1.GetHashCode(), d2.GetHas

给定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
,但这还不够。可以重写方法调用基类方法。这不算作值语义

顺便说一句,值语义并不意味着相等的哈希代码。这也可能是一次碰撞;值语义意味着两个具有equals属性的对象应该返回相同的hashcode,并且equals方法的计算结果应该为true


我建议您创建一个实例,分配一些属性,克隆它;现在两个hashcode应该相等,调用
object.Equals(original,clone)
的值应该为true

您可以通过以下方法测试
Equals()
GetHashCode()
的实现:

s.GetType().GetMethod("GetHashCode").DeclaringType == s.GetType()
或者按照@hvd的建议:

s.GetType().GetMethod("GetHashCode").DeclaringType != typeof(object)
某些对象,如果未按其类型实现
GetHashCode()
,则为false,否则为true

需要注意的一点是,这将无法防止
Equals()
GetHashCode()
的糟糕实现—即使实现是
public override int GetHashCode(){}
,这也将评估为true


鉴于这些缺点,我倾向于记录您的类型(“此类型应该/不应该用于字典键…”),因为这不是您最终可以依赖的东西。如果
Equals()

您可以使用相应
MethodInfo
上的
DeclaringType
属性查看对象是否定义了自己的
等于
GetHashCode

bool definesEquality = type.GetMethod("Equals", new[] { typeof(object) }).DelcaringType == type && type.GetMethod("GetHashCode", Type.EmptyTypes).DeclaringType == type;

您可以基于
IEquatable
创建泛型约束。具有默认引用等式的类型非常适合字典键。更简单的是:
instance.GetHashCode()==RuntimeHelpers.GetHashCode(instance)
。它告诉您返回的哈希代码是否与非重写
对象使用的哈希代码相同。但是,对于值类型来说,它不是很有意义,但应该可以工作(新框的哈希代码)。请注意,哈希代码相同可能是“意外”(偶然);但是您需要使用完全相同的对象来检索值。在大多数情况下,这不太可能有帮助。我认为这是一个你应该尝试用文档而不是反思来解决的问题。您应该向消费方清楚地表明,您期望一些能够正确实现哈希和可均衡性的东西,应该是这样。这不算作值语义。重写的方法可以简单地调用基本实现(可以使用引用比较)。@SriramSakthivel-是的,这只回答了标题中的问题。您可能想要
!=typeof(object)
,而不是
==s.GetType()
。不同的基类可能已经以合理的方式重写了该方法。@hvd这是一个好主意,但这不是用一种“可能的情况”换另一种吗?是的,我已经对为什么我认为OP应该完全放弃这种方法的问题发表了评论。:)但是,如果OP无论如何都想这么做,我认为将基类重写视为可能具有值语义更符合OP的要求。我明白你的意思。我同意你的所有回答,但我想强调的是创建实例、分配一些属性、克隆、,然后比较哈希码是不可靠的。根据hashcode的实现方式,对于某些hashcode来说,一个坏掉的实现仍然可以正常运行(如果你运气不好,那么这些就是你最终要测试的部分)。@Asad Good point;如果hashcode的实现被破坏,那么OP应该在编写这个方法之前修复它。我也不确定写这个测试是否明智。当他决定添加一个类型作为字典的键时,他可以确保该类型具有值语义。IMO不需要对此进行测试。我们一直在这样做,从未编写过检查值语义的测试。OP试图测试他们的API的某些使用者是否在作为类型参数传递给OP代码的类型中正确实现了值语义。我不认为OP有任何方法可以修复它,如果它坏了。我的观点是,OP甚至没有万无一失的方法来检测哈希是否得到了正确的实现,所以最好在文档中声明“实现哈希和可均衡性,或者其他”,然后就不说了。谢谢大家的讨论。我肯定会在API文档中包含这些要求。