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? I guess it's a field having a reference type but I'm not sure.
有人可以澄清“GC参考”的含义吗?我猜这是一个有引用类型的字段,但我不确定。
If I create a struct
which only has value type fields, will the instances of it be always compared the fast way?
如果我创建一个只有值类型字段的结构,它的实例是否总是与快速方式进行比较?
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的文档已得到显着改进:它没有提到的矛盾,现在可以更好地理解默认值类型相等性检查的工作原理。
2 个解决方案
#1
36
ValueType is special. It does this:
ValueType很特别。它这样做:
- If the obj comparing to is null, it returns false.
- 如果obj比较为null,则返回false。
- If the this and obj arguments are different types, it returns false.
- 如果this和obj参数是不同的类型,则返回false。
- It uses reflection to call Equals on each instance field for each value, if any of those fields are not equal, it returns false. Otherwise it return true, never calling ValueTypes base.Equals (which is object.Equals).
- 它使用反射在每个值的每个实例字段上调用Equals,如果这些字段中的任何一个不相等,则返回false。否则返回true,从不调用ValueTypes base.Equals(即object.Equals)。
Because it uses reflection to compare the fields, you should always override Equals
on any ValueType
you create. Reflection is slow.
因为它使用反射来比较字段,所以您应该始终在您创建的任何ValueType上重写Equals。反思很慢。
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. It has to do this, because the struct actually has a pointer to the reference type's location on the heap.
当它是“GCReference”或结构中作为参考类型的字段时,它会在每个字段上使用反射进行比较。它必须这样做,因为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, i.e. a struct with only one int
field, no reflection is done during a comparison. None of the fields reference anything on the heap, so there is no GCReference
or GCHandle
. 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.
对于仅具有字段值类型的结构,即只有一个int字段的结构,在比较期间不进行反射。没有字段引用堆上的任何内容,因此没有GCReference或GCHandle。此外,此结构的任何实例都将具有相同的字段内存布局(有一些小的例外),因此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. Keep reading.
所以,是的,如果您的结构中只有值类型,它将执行更快的memcmp,而不是反射比较,但您可能不想这样做。继续阅读。
This does not mean you should use the default equals
implementation. 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:
这并不意味着您应该使用默认的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
}
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的默认实现
#2
0
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. So reflection will be used. This part of the text seems to say I am right:
没有反射就无法比较ObjectTest。因此将使用反射。文本的这一部分似乎说我是对的:
"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和此实例的相应字段。”
#1
36
ValueType is special. It does this:
ValueType很特别。它这样做:
- If the obj comparing to is null, it returns false.
- 如果obj比较为null,则返回false。
- If the this and obj arguments are different types, it returns false.
- 如果this和obj参数是不同的类型,则返回false。
- It uses reflection to call Equals on each instance field for each value, if any of those fields are not equal, it returns false. Otherwise it return true, never calling ValueTypes base.Equals (which is object.Equals).
- 它使用反射在每个值的每个实例字段上调用Equals,如果这些字段中的任何一个不相等,则返回false。否则返回true,从不调用ValueTypes base.Equals(即object.Equals)。
Because it uses reflection to compare the fields, you should always override Equals
on any ValueType
you create. Reflection is slow.
因为它使用反射来比较字段,所以您应该始终在您创建的任何ValueType上重写Equals。反思很慢。
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. It has to do this, because the struct actually has a pointer to the reference type's location on the heap.
当它是“GCReference”或结构中作为参考类型的字段时,它会在每个字段上使用反射进行比较。它必须这样做,因为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, i.e. a struct with only one int
field, no reflection is done during a comparison. None of the fields reference anything on the heap, so there is no GCReference
or GCHandle
. 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.
对于仅具有字段值类型的结构,即只有一个int字段的结构,在比较期间不进行反射。没有字段引用堆上的任何内容,因此没有GCReference或GCHandle。此外,此结构的任何实例都将具有相同的字段内存布局(有一些小的例外),因此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. Keep reading.
所以,是的,如果您的结构中只有值类型,它将执行更快的memcmp,而不是反射比较,但您可能不想这样做。继续阅读。
This does not mean you should use the default equals
implementation. 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:
这并不意味着您应该使用默认的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
}
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的默认实现
#2
0
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. So reflection will be used. This part of the text seems to say I am right:
没有反射就无法比较ObjectTest。因此将使用反射。文本的这一部分似乎说我是对的:
"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和此实例的相应字段。”