这两个文档页面似乎与此主题相矛盾:
它是按位平等还是反思?
我瞥了一眼源代码,ValueType
发现评论说
//如果此对象中没有GC引用,我们可以避免反射
//并做一个快速的memcmp
有人可以澄清"GC参考"的含义吗?我想这是一个有引用类型的字段,但我不确定.
如果我创建一个struct
只有值类型字段,那么它的实例是否总是与快速方式进行比较?
更新: .Net 4.5的文档已得到显着改进:它没有提到的矛盾,现在可以更好地理解默认值类型相等性检查的工作原理.
Chr*_*ens 43
System.ValueType.Equals
很特别.它按顺序执行以下步骤,直到获得一些结果:
obj
比较为'null',则返回false
.this
和obj
参数是不同的类型,则返回false
.true
.Equals
为每个值调用配对的实例字段.如果这些字段中的任何一个不相等,则返回false
.否则它会返回true
.请注意,它从不调用基本方法Object.Equals
.因为它使用反射来比较字段,所以应始终覆盖 您创建的Equals
任何字段ValueType
.反思很慢.
当它是"GCReference"或结构中作为参考类型的字段时,它会使用每个字段上的反射来进行比较.它必须这样做,因为它struct
实际上有一个指向引用类型在堆上的位置的指针.
如果结构中没有使用引用类型,并且它们是相同的类型,则保证字段的顺序相同,并且内存中的大小相同,因此它只能比较裸内存.
对于仅具有字段值类型的结构,即只包含一个int
字段的结构,在比较期间不进行反射.没有字段引用堆上的任何内容,因此没有GCReference
或GCHandle
.此外,此结构的任何实例都将具有相同的字段内存布局(有一些小的例外),因此CLR团队可以进行直接内存比较(memcmp),这比其他选项快得多.
所以,是的,如果您的结构中只有值类型,它将执行更快的memcmp,而不是反射比较,但您可能不想这样做.继续阅读.
这并不意味着您应该使用默认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
}
Run Code Online (Sandbox Code Playgroud)
数字在数学上是相等的,但它们的二进制表示不相等.所以,我会再次强调它,不要依赖ValueType.Equals的默认实现