Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/linq/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 什么时候是Double';s==调用的运算符?_C#_.net - Fatal编程技术网

C# 什么时候是Double';s==调用的运算符?

C# 什么时候是Double';s==调用的运算符?,c#,.net,C#,.net,这一切都是从有人向我提出的一个问题开始的。。(简而言之,书中提到了这一点)这里是它的要点 Double a = Double.NaN; Console.WriteLine(a == a); // => false Console.WriteLine(a.Equals(a)); // => true 上面的说法似乎不对。a应该始终为==自身(引用相等)&两者应该一致 似乎双重重载==运算符。由反射镜确认如下: [__DynamicallyInvokable] public stati

这一切都是从有人向我提出的一个问题开始的。。(简而言之,书中提到了这一点)这里是它的要点

Double a = Double.NaN;
Console.WriteLine(a == a); // => false
Console.WriteLine(a.Equals(a)); // => true
上面的说法似乎不对。a应该始终为==自身(引用相等)&两者应该一致

似乎双重重载==运算符。由反射镜确认如下:

[__DynamicallyInvokable]
public static bool operator ==(double left, double right)
{
    return (left == right);
}
奇怪的是,它看起来是递归的,并且没有提到NaN特定的行为。那么为什么它会返回false呢

所以我添加了一些代码来区分

var x = "abc";
var y = "xyz";
Console.WriteLine(x == y); // => false
现在我明白了

    L_0001: ldc.r8 NaN
    L_000a: stloc.0 
    L_000b: ldloc.0 
    L_000c: ldloc.0 
    L_000d: ceq 
    L_000f: call void [mscorlib]System.Console::WriteLine(bool)
    L_0014: nop 
    L_0015: ldloca.s a
    L_0017: ldloc.0 
    L_0018: call instance bool [mscorlib]System.Double::Equals(float64)
    L_001d: call void [mscorlib]System.Console::WriteLine(bool)
    L_0022: nop 
    L_0023: ldstr "abc"
    L_0028: stloc.1 
    L_0029: ldstr "xyz"
    L_002e: stloc.2 
    L_002f: ldloc.1 
    L_0030: ldloc.2 
    L_0031: call bool [mscorlib]System.String::op_Equality(string, string)
    L_0036: call void [mscorlib]System.Console::WriteLine(bool)
  • 对于双工,==操作员调用转换为
    ceq
    IL操作码
  • 其中,对于字符串,它转换为System.String::op_Equality(字符串,字符串)
确实,指定它是浮点数和NaN的特殊情况。这就解释了观察结果

问题:

  • 为什么在Double上定义op_等式?(并且实现不考虑特定于NaN的行为)
  • 何时调用
反射器的错误解释 从Reflector看到的反编译实际上是Reflector中的一个bug。Reflector需要能够反编译一个函数,其中比较两个双精度函数;在这些函数中,您会发现
ceq
被直接发送到代码中。因此,Reflector将
ceq
指令解释为==介于两个双精度之间,以帮助反编译比较两个双精度的函数

默认情况下,值类型没有==实现。()但是,所有内置标量类型都有一个显式重载运算符,编译器将其转换为相应的CIL。重载还包含一个简单的基于
ceq
的比较,这样==操作符重载的动态/后期绑定/基于反射的调用就不会失败


更多细节 对于预定义的值类型,如果 其操作数的值相等,否则为false。供参考 字符串以外的类型,==如果其两个操作数引用 同一个物体。对于字符串类型,==比较 字符串

--

您所说的意味着==使用引用类型语义来比较
double
。但是,由于
double
是一种值类型,因此它使用值语义。这就是为什么
3==3
是真的,即使它们是不同的堆栈对象

您几乎可以将此编译器转换视为LINQ的可查询对象如何包含包含代码的扩展方法,但编译器将这些调用转换为表达式树,并将其传递给LINQ提供程序。在这两种情况下,底层函数从未真正被调用


Double的比较语义 Double的文档确实提到了
ceq
CIL指令的工作原理:

如果通过调用Equals方法测试两个Double.NaN值是否相等,则该方法返回true。但是,如果使用相等运算符测试两个NaN值是否相等,则运算符将返回false。当您想要确定Double的值是否不是数字(NaN)时,另一种方法是调用IsNaN方法

--


原始编译器源代码 如果查看反编译的C#编译器源代码,您将发现以下代码,用于将双重比较直接转换为
ceq

private void EmitBinaryCondOperator(BoundBinaryOperator binOp, bool sense)
{
    int num;
    ConstantValue constantValue;
    bool flag = sense;
    BinaryOperatorKind kind = binOp.OperatorKind.OperatorWithLogical();
    if (kind <= BinaryOperatorKind.GreaterThanOrEqual)
    {
        switch (kind)
        {
            ...

            case BinaryOperatorKind.Equal:
                goto Label_0127;

            ...
        }
    }
...
Label_0127:
    constantValue = binOp.Left.ConstantValue;
    if (((constantValue != null) && constantValue.IsPrimitiveZeroOrNull) && !constantValue.IsFloating)
    {
        ...
        return;
    }
    constantValue = binOp.Right.ConstantValue;
    if (((constantValue != null) && constantValue.IsPrimitiveZeroOrNull) && !constantValue.IsFloating)
    {
        ...
        return;
    }
    this.EmitBinaryCondOperatorHelper(ILOpCode.Ceq, binOp.Left, binOp.Right, sense);
    return;
}
private void EmitBinaryCondOperator(BoundBinaryOperator binOp,bool sense)
{
int-num;
康斯坦特价值康斯坦特价值;
布尔标志=感觉;
BinaryOperatorKind-kind=binOp.OperatorKind.OperatorWithLogical();
如果(种类来自msdn:

如果通过调用Equals测试两个Double.NaN值是否相等 方法,则该方法返回true。但是,如果测试了两个NaN值 对于使用相等运算符的相等,运算符返回 false。当您要确定Double的值是否为空时 一个数字(NaN),另一种方法是调用IsNaN方法

其中规定:

如果通过调用Equals测试两个Double.NaN值是否相等 方法,则该方法返回true。但是,如果测试了两个NaN值 对于使用相等运算符的相等,运算符返回 false。当您要确定Double的值是否为空时 一个数字(NaN),另一种方法是调用IsNaN方法

这是为了符合IEC 60559:1989,因为它规定两个NaN值不相等,因为它们不被视为数字,所以
op_equal
定义符合本标准

根据IEC 60559:1989,两个浮点数的值为 NaN永远不相等。但是,根据 Object::Equals方法,最好重写此方法 提供值相等语义。因为System.ValueType提供 此功能通过使用反射,对 具体地说,应该考虑价值类型。 重写默认ValueType实现以获得性能 增加。事实上从源头上看 System.ValueType::Equals(clr\src\BCL\System\ValueType.cs的第36行 在SSCLI)中,CLR Perf团队甚至向 System.ValueType::的效果等于不快


请参阅:

Reflector在这种情况下通常会失败。我猜
操作符==
不会调用自身,而是在内部使用
ceq
。我猜这与@jbl是同一个问题-这个问题是问为什么2个相等返回不同的结果-我似乎已经弄明白了。我的问题是关于看似重复的结果dant静态op_相等实现,似乎从未被调用过。非常详细的回答。因此,为了总结您的响应,调用了Double::op_相等运算符,但由