简体   繁体   English

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

[英]In .NET 4.0, What is the default implementation of Equals for value types?

The two documentation pages seem to contradict on this topic: 这两个文档页面似乎与此主题相矛盾:

  • ValueType.Equals Method says "The default implementation of the Equals method uses reflection to compare the corresponding fields of obj and this instance." ValueType.Equals方法说“Equals方法的默认实现使用反射来比较obj和这个实例的相应字段。”
  • Object.Equals Method (Object) says "The default implementation of Equals supports reference equality for reference types, and bitwise equality for value types ." Object.Equals Method(Object)说“Equals的默认实现支持引用类型的引用相等,以及值类型的按位相等 ”。

So is it bitwise equality or reflection? 它是按位平等还是反思?

I took a glimpse at the source code of ValueType and found a comment saying ValueType的源代码,发现了一条评论说

// if there are no GC references in this object we can avoid reflection //如果此对象中没有GC引用,我们可以避免反射

// and do a fast memcmp //并做一个快速的memcmp

Can someone clarify what "GC reference" means? 有人可以澄清“GC参考”的含义吗? I guess it's a field having a reference type but I'm not sure. 我想这是一个有引用类型的字段,但我不确定。

If I create a struct which only has value type fields, will the instances of it be always compared the fast way? 如果我创建一个只有值类型字段的struct ,它的实例总是会以快速的方式进行比较吗?

UPDATE: The documentation for.Net 4.5 has been significantly improved: it is free from the mentioned contradiction and now gives a better understanding how the default value type equality checking works. 更新: .Net 4.5的文档已得到显着改进:它没有提到的矛盾,现在可以更好地理解默认值类型相等性检查的工作原理。

System.ValueType.Equals is special. System.ValueType.Equals很特殊。 It does the following steps, in order, until it gets some result: 它按顺序执行以下步骤,直到获得一些结果:

  1. If the obj comparing to is 'null', it returns false . 如果obj比较为'null',则返回false
  2. If the this and obj arguments are different types, it returns false . 如果thisobj参数是不同的类型,则返回false
  3. If the type is "blittable" it compares the memory images. 如果类型是“blittable”,它会比较内存图像。 If they are identical, it returns true . 如果它们相同,则返回true
  4. Finally, it uses reflection to call Equals the paired-up instance fields for each value. 最后,它使用反射为每个值调用Equals配对实例字段。 If any of those fields are not equal, it returns false . 如果这些字段中的任何一个不相等,则返回false Otherwise it returns true . 否则返回true Note that it never calls the base method, Object.Equals . 请注意,它从不调用基本方法Object.Equals

Because it uses reflection to compare the fields, you should always override Equals on any ValueType you create. 因为它使用反射来比较字段,所以应始终在您创建的任何ValueType重写 Equals Reflection is slow. 反思很慢。

When it's a "GCReference", or a field in the struct that is a reference type, it winds up using reflection on each field to do the comparison. 当它是“GCReference”或结构中作为参考类型的字段时,它会在每个字段上使用反射进行比较。 It has to do this, because the struct actually has a pointer to the reference type's location on the heap. 它必须这样做,因为struct实际上有一个指向引用类型在堆上的位置的指针。

If there is no reference type used in the struct, and they are the same type, the fields are guaranteed to be in the same order, and be the same size in memory, so it can just compare the bare memory. 如果结构中没有使用引用类型,并且它们是相同的类型,则保证字段的顺序相同,并且内存中的大小相同,因此它只能比较裸存储器。

For a struct with only value types for fields, ie a struct with only one int field, no reflection is done during a comparison. 对于仅具有字段值类型的结构,即只有一个int字段的结构,在比较期间不进行反射。 None of the fields reference anything on the heap, so there is no GCReference or GCHandle . 没有字段引用堆上的任何内容,因此没有GCReferenceGCHandle Furthermore, any instance of this structure will have the same in-memory layout of the fields (with a few minor exceptions), so the CLR team can do a direct memory comparison (memcmp), which is much faster than the other option. 此外,此结构的任何实例都将具有相同的字段内存布局(有一些小的例外),因此CLR团队可以进行直接内存比较(memcmp),这比其他选项快得多。

So yes, if you only have value types in your structure, it will do the faster memcmp, instead of the reflection comparison, but you may not want to do that. 所以,是的,如果您的结构中只有值类型,它将执行更快的memcmp,而不是反射比较,但您可能不想这样做。 Keep reading. 继续阅读。

This does not mean you should use the default Equals implementation. 并不意味着您应该使用默认的Equals实现。 In fact, do not do that. 事实上,不要这样做。 Stop it. 停下来。 It's doing bit comparisons, which are not always accurate. 它正在进行比较,这并不总是准确的。 What is that you say? 你说的是什么? Let me show you: 让我演示给你看:

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
}

The numbers are equal mathematically, but they are not equal in their binary representation. 数字在数学上是相等的,但它们的二进制表示不相等。 So, I will stress it again, do not rely on the default implementation of ValueType.Equals 所以,我会再次强调它, 不要依赖ValueType.Equals的默认实现

Not being a real expert in this field I would just go ahead and put my thoughts: The documentation (according to me) states that if your struct has a field that is object (reference type) reflection can not be avoided. 不是这个领域的真正专家我会继续并提出我的想法:文档(据我所知)指出,如果你的结构有一个对象(引用类型)的字段,则无法避免反射。

So if you have the following: 所以如果你有以下内容:

    public struct SomeStruct
    {
        public object ObjectTest
    }

The ObjectTest cannot be compared without reflection. 没有反射就无法比较ObjectTest。 So reflection will be used. 因此将使用反射。 This part of the text seems to say I am right: 这部分内容似乎说我是对的:

" ValueType.Equals - The default implementation of the Equals method uses reflection to compare the corresponding fields of obj and this instance." ValueType.Equals - Equals方法的默认实现使用反射来比较obj和此实例的相应字段。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM