任何测试结构(尤其是包含“十进制”)的精确相等的好方法

Any nice way to test structures (esp containing `Decimal`) for exact equality

提问人:supercat 提问时间:11/19/2012 最后编辑:supercat 更新时间:11/20/2012 访问量:140

问:

在 4.0 之前的 .net 版本中,如果结构仅包含基元字段,则仅当所有字段都精确匹配时,结构的运算符才会返回。在 4.0 中,Microsoft 更改了此行为,以便具有类型字段的结构可以返回 true,如果相应的字段包含表示相同数值的值,即使它们在其他细节上不匹配(最值得注意的是,对于 ,仅在尾随零中不同的值被视为相等)。不幸的是,在某些情况下,这绝对是灾难性的。例如,给定两个不可变对象 和 ,如果 的所有字段都与 的字段完全匹配,则应该可以替换 。然而,为了保证这种换人的安全,比赛必须精确。如果 中的字段包含 0.1m,而 中的相应字段包含 0.10m,则不应将对象视为相等,因为 的可观察行为与 的可观察行为不同。EqualstrueDecimalDecimalXYYXXYXYYX

如果 Microsoft 没有覆盖这些类型以表示等价以外的其他含义(这是几乎所有其他类型的意思),则可以安全地假设,如果一个对象报告它是另一个对象,则后者的实例可以替代前者;即使给定了 上的非等价覆盖,也可以通过将这些类型包装在一个结构中来测试等价性。鉴于Microsoft不再允许这种等效性测试方法,必须做些什么才能获得相同的结果?是否有任何方法可以确定属性是定义自己的重写 [应该使用] 还是系统提供的重写 [在这种情况下,如果结构包含任何使用非等价的字段,它应该使用测试等价的相等运算符]?EqualsEqualsDecimalAlternateEqualityComparer<T>.DefaultObject.EqualsEquals

编辑我使用包含浮点类型以及 ;即使不是引用类型,它在结构中的存在也会导致自动生成的方法不对任何字段使用二进制比较。DecimalDecimalEquals

编辑 2下面是一个示例程序,显示了 .net 4.0 中的问题;我读到自早期版本的 .net 以来,该行为已发生变化,尽管该程序似乎在 2.0 和 4.0 上运行相同:

struct Test<T1,T2>
{
    public T1 f1;
    public T2 f2;
    public Test(T1 p1, T2 p2)
    {
        f1 = p1;
        f2 = p2;
    }
}

class Program
{
    static void DoCompares<T1,T2>(Test<T1,T2> thing1, Test<T1,T2> thing2)
    {
        Console.WriteLine("{0}/{1}/{2} {3}",
        thing1.f1, thing2.f1, thing1.f1.Equals((Object)thing2.f1),
        thing1.Equals(thing2));
    }
    static void DoTest<T1, T2>(T1 p1a, T1 p1b, T2 p2)
    {
        Test<T1,T2> thing1 = new Test<T1,T2>(p1a,p2);
        Test<T1,T2> thing2 = new Test<T1,T2>(p1b,p2);
        DoCompares(thing1, thing2);
    }
    static void Main(string[] args)
    {
        DoTest(1.0m, 1.00m, 1.0);
        DoTest(1.0m, 1.00m, 1.0m);
        DoTest(1.0 / (1.0 / 0.0), -1.0 / (1.0 / 0.0), 1.0m);
        DoTest(1.0 / (1.0 / 0.0), -1.0 / (1.0 / 0.0), 1.0);
        Console.ReadLine();
    }
}

如果结构仅包含类型,则结构的相等比较器会报告结构不完全匹配。如果它包含一个类型的字段,即使它是一个不包含引用字段的结构,那么如果它们的数值相等,即使它们不等效,相等比较器也会将它们报告为相同。DoubleDecimalDecimal

无论如何,无论 .net 是否曾经坚持对对象进行二进制匹配,问题仍然存在:执行结构比较的最佳方法是什么,以便使用按位相等而不是数值相等来确定不包含引用类型字段的值类型的相等比较?有没有办法尊重结构类型的“显式”覆盖,同时为那些自动生成的结构类型使用替代相等比较器?DecimalEqualsEquals

.NET 结构 相等

评论

0赞 Damien_The_Unbeliever 11/19/2012
我不确定你是如何陷入这样的情况的,无论是输入是 or ,都会产生不同的行为,但你不是在尝试解决错误的问题吗?0.1m0.10m
1赞 Jon 11/19/2012
我也不确定你提到的是否正确。当前文档说,如果当前实例和 obj 的字段都不是引用类型,则 Equals 方法将对内存中的两个对象执行逐字节比较。位相同是尽可能相同的。我是否误解了这个问题?
0赞 Serge Belov 11/19/2012
我刚刚测试了具有正零和负零的 Equals,似乎它们在 4.0(使用 VS 2012 编译)下进行了逐位比较,即双负零字段使结构不等于具有双正零字段的结构。
0赞 supercat 11/19/2012
@Jon:我想仍然使用二进制比较,但没有;当我写这个问题时,我想,因为 Decimal 的 struct-equals 行为现在反映了它(不幸的)覆盖行为,那么 / 也会......让我重新表述这个问题。doubleDecimalEqualsdoublefloat
0赞 supercat 11/19/2012
@SergeBelov:如果结构包含 类型的字段,即使该字段不是引用类型,它也不会对浮点字段使用二进制比较。Decimal

答: 暂无答案