“乌龙==乌龙?”评估为“ ulong == ulong”可以正常工作

时间:2019-10-15 11:59:46

标签: c# operator-overloading nullable equals-operator

如果我们在表达式==和表达式ulong之间使用ulong?运算符,则似乎会使用运算符重载bool ulong(ulong left, ulong right)

Showing use of == operator

换句话说,运算符认为两个表达式都不为空。

在此示例程序中,equal正确地变为假,没有例外。

void Main()
{
    var temp = new Temp(0);
    object temp2 = null;

    var equal = temp.Id == (temp2 as Temp)?.Id; // False :) but how?
}

public class Temp
{
    public ulong Id {get;}

    public Temp(ulong id)
    {
        this.Id = id;
    }
}
  1. 这怎么不丢?没有将值从ulong?转换为ulong的转换。 (ulong)(ulong?)null引发:“可为空的对象必须具有一个值。”
  2. 这是否为ulong?所有可能值返回正确的值,包括空值?如果是这样,怎么办?类型ulong?的可能值比ulong多,因此应该有一组两个值映射到 same ulong值,这将引入一个假阳性“真实”结果。

从理论上讲,我可以想象null会合并到default(ulong),但是上面示例中的结果将是正确的,这将是错误的答案。正如我们所看到的,编译器不会犯该错误-它会正确回答。

2 个答案:

答案 0 :(得分:9)

来自MSDN

  

提升运算符 允许对非空值类型进行操作的预定义和用户定义运算符也可以与这些类型的可空形式一起使用。提升的运算符由满足特定要求的预定义和用户定义的运算符构造而成,如下所述:

     

...

     
      
  • 对于相等运算符

    ==  !=
    
  •   
     

如果操作数类型都是非空值类型,并且结果类型为bool,则存在提升形式的运算符。通过向每种操作数类型添加单个?修饰符来构造提升形式。提升运算符认为两个空值相等,并且一个空值不等于任何非空值。如果两个操作数都不为空,则提升操作符将取消包装操作数并应用基础操作符以生成bool结果。

您不使用运算符:

bool ==(ulong left, ulong right)

您正在使用提升运算符:

bool ==(ulong? left, ulong? right)

该运算符采用两个ulong?参数,如果两个参数均为null,或者两个参数均为非null且具有相同的值,则返回true。


您可能正在看Visual Studio,在这种情况下确实显示出一些令人困惑的地方:

Visual Studio screenshot

不要对此感到困惑-@mjwills在评论this is a known issue中指出。


如果您这样写:

public bool M(ulong a, ulong? b) {
    return a == b;
}

然后,编译器将生成以下代码:

public bool M(ulong a, ulong? b)
{
    ulong? num = b;
    return (a == num.GetValueOrDefault()) & num.HasValue;
}
如果num.GetValueOrDefault()0,则

b返回null,否则返回b的值。因此,M仅在true不为null且与b相同的情况下才返回a

SharpLab

答案 1 :(得分:7)

  

如果我们在ulong表达式和an表达式之间使用==运算符   ulong?的表达式,则运算符将布尔ulong(ulong   左,乌龙右)。

问题的很大一部分是Visual Studio的智能感知错误地显示了ulong的{​​{1}}运算符正在使用(如果将鼠标悬停在==上)。

根据https://github.com/dotnet/roslyn/issues/21494,这是一个错误。实际上不是使用该运算符。

由于您所有其他问题均基于该错误前提,因此意识到该错误的存在会使其他问题在很大程度上消失。