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

标签 c# .net clr

两个文档页面似乎在这个主题上自相矛盾:

那么是按位相等还是反射?

我瞥了一眼ValueType的源代码,发现有评论说

// if there are no GC references in this object we can avoid reflection

// and do a fast memcmp

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

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

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

最佳答案

System.ValueType.Equals很特别。它按顺序执行以下步骤,直到得到一些结果:

  1. 如果 obj 比较为“null”,则返回 false
  2. 如果 thisobj 参数是不同的类型,则返回 false
  3. 如果类型是“blittable”,它会比较内存镜像。如果它们相同,则返回 true
  4. 最后,它使用反射调用 Equals 每个值的配对实例字段。如果这些字段中的任何一个不相等,则返回 false。否则返回 true。请注意,它从不调用基方法 Object.Equals

因为它使用反射来比较字段,所以您应该始终覆盖 Equals 您创建的任何 ValueType .反射很慢。

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

如果struct中没有使用引用类型,并且它们是同一类型,则保证字段的顺序相同,并且在内存中的大小相同,因此它可以只比较裸内存。

对于字段只有值类型的结构,即只有一个 int 字段的结构,比较期间不会进行反射。没有字段引用堆上的任何内容,因此没有 GCReferenceGCHandle。此外,此结构的任何实例都将具有相同的字段内存布局(有一些小异常(exception)),因此 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
}

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

关于c# - 在 .NET 4.0 中,值类型的 Equals 默认实现是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8315656/

相关文章:

c# - C# 中的线程安全属性

.net - 递归泛型类型的实例化速度越慢,嵌套越深。为什么?

c# - 尝试减少 GC 收集

c# - 在单元测试中检测垃圾

c# - CLR 编译器优化示例

c# - iis工作进程内存使用率与处置对象之间的关系?

c# - 将某人的本地时间转换为 UTC 时间

c# - 从控制台应用程序远程连接到 RDC 服务器需要引用什么库?

c# - CIL是汇编语言,JIT是汇编程序吗

c# - .NET Core 2.0 中的位图图像