在.NET 4.0中,值类型的Equals的默认实现是什么?

这两个文档页面似乎与此主题相矛盾:

  • ValueType.Equals方法说“Equals方法的默认实现使用reflection来比较obj和这个实例的相应字段。”
  • Object.Equals Method(Object)说“Equals的默认实现支持引用类型的引用相等,以及值类型的按位相等 ”。

它是按位平等还是反思?

ValueType的源代码,发现评论说

//如果此对象中没有GC引用,我们可以避免reflection

//并做一个快速的memcmp

有人可以澄清“GC参考”的含义吗? 我猜这是一个有引用类型的字段,但我不确定。

如果我创建一个只有值类型字段的struct ,它的实例是否总是与快速方式进行比较?

更新: .Net 4.5的文档已得到显着改进:它没有提到的矛盾,现在可以更好地理解默认值类型相等性检查的工作原理。

ValueType很特别。 它这样做:

  1. 如果obj比较为null,则返回false。
  2. 如果this和obj参数是不同的类型,则返回false。
  3. 它使用reflection在每个值的每个实例字段上调用Equals,如果这些字段中的任何一个不相等,则返回false。 否则返回true,从不调用ValueTypes base.Equals(即object.Equals)。

因为它使用reflection来比较字段,所以您应该始终在您创建的任何ValueType上重写Equals 。 反思很慢。

当它是“GCReference”或结构中作为参考类型的字段时,它会在每个字段上使用reflection进行比较。 它必须这样做,因为struct实际上有一个指向引用类型在堆上的位置的指针。

如果结构中没有使用引用类型,并且它们是相同的类型,则保证字段的顺序相同,并且内存中的大小相同,因此它只能比较裸存储器。

对于仅具有字段值类型的结构,即只有一个int字段的结构,在比较期间不会进行reflection。 没有字段引用堆上的任何内容,因此没有GCReferenceGCHandle 。 此外,此结构的任何实例都将具有相同的字段内存布局(有一些小的例外),因此CLR团队可以进行直接内存比较(memcmp),这比其他选项快得多。

所以,是的,如果您的结构中只有值类型,它将执行更快的memcmp,而不是reflection比较,但您可能不想这样做。 继续阅读。

并不意味着您应该使用默认的equals实现。 事实上,不要这样做。 停下来。 它正在进行比较,这并不总是准确的。 你说的是什么? 让我演示给你看:

 private struct MyThing { public float MyFloat; } private static void Main(string[] args) { MyThing f, s; f.MyFloat = 0.0f; s.MyFloat = -0.0f; Console.WriteLine(f.Equals(s)); // prints False Console.WriteLine(0.0f == -0.0f); // prints True } 

数字在数学上是相等的,但它们的二进制表示不相等。 所以,我会再次强调它, 不要依赖ValueType.Equals的默认实现

不是这个领域的真正专家我会继续并提出我的想法:文档(据我所知)指出,如果你的结构有一个对象(引用类型)的字段,则无法避免reflection。

所以如果你有以下内容:

  public struct SomeStruct { public object ObjectTest } 

没有reflection就无法比较ObjectTest。 因此将使用reflection。 文本的这一部分似乎说我是对的:

ValueType.Equals – Equals方法的默认实现使用reflection来比较obj和此实例的相应字段。”