以下是带注释的示例:

class Program
{
    // first version of structure
    public struct D1
    {
        public double d;
        public int f;
    }

    // during some changes in code then we got D2 from D1
    // Field f type became double while it was int before
    public struct D2 
    {
        public double d;
        public double f;
    }

    static void Main(string[] args)
    {
        // Scenario with the first version
        D1 a = new D1();
        D1 b = new D1();
        a.f = b.f = 1;
        a.d = 0.0;
        b.d = -0.0;
        bool r1 = a.Equals(b); // gives true, all is ok

        // The same scenario with the new one
        D2 c = new D2();
        D2 d = new D2();
        c.f = d.f = 1;
        c.d = 0.0;
        d.d = -0.0;
        bool r2 = c.Equals(d); // false! this is not the expected result        
    }
}

那么,你怎么看?

推荐答案

错误位于下面两行System.ValueType行中:(我进入了参考源)

if (CanCompareBits(this)) 
    return FastEqualsCheck(thisObj, obj);

(两种方法都是[MethodImpl(MethodImplOptions.InternalCall)])

当所有字段都是8字节宽时,CanCompareBits错误地返回TRUE,从而导致对两个不同但语义相同的值进行逐位比较.

当至少有一个字段不是8字节宽时,CanCompareBits返回false,代码继续使用反射在字段上循环,并 for each 值调用Equals,这将正确地将-0.0视为等于0.0.

以下是来自SSCLI的CanCompareBits美元的来源:

FCIMPL1(FC_BOOL_RET, ValueTypeHelper::CanCompareBits, Object* obj)
{
    WRAPPER_CONTRACT;
    STATIC_CONTRACT_SO_TOLERANT;

    _ASSERTE(obj != NULL);
    MethodTable* mt = obj->GetMethodTable();
    FC_RETURN_BOOL(!mt->ContainsPointers() && !mt->IsNotTightlyPacked());
}
FCIMPLEND

.net相关问答推荐

将多行参数传递给Power Shell中的DotNet Pack命令

Msbuild try 构建 msbuild.exe 而不是我的 .csproj 文件

为什么这个同步运行的异步睡眠会挂起?

使属性只能通过绑定的 Editor(component) 编辑

即时窗口中的动态导致Microsoft.CSharp.RuntimeBinder.Binder未定义或导入错误

Gacutil.exe 成功添加程序集,但在资源管理器中无法查看程序集.为什么?

将毫秒转换为人类可读的时间间隔

在 C# 中将字节数组保存为磁盘上的文件的最有效方法是什么?

在 C# DllImport 中使用 32 位或 64 位 dll

找不到 Microsoft.Office.Interop Visual Studio

覆盖方法上的 C# 可选参数

从 List 到数组 T[] 的转换

Convert.ToBoolean 和 Boolean.Parse 不接受 0 和 1

DataGridView 在我的两个屏幕之一上的可怕重绘性能

在 .NET 中获取默认打印机的最佳方法是什么

通过反射查找可空属性的类型

无锁多线程适用于真正的线程专家

SqlCommand.CommandTimeout 和 SqlConnection.ConnectionTimeout 有什么区别?

检测到包降级警告(dotnet core,vs 2017)

如何将我的应用程序窗口置于最前面?