If we use the == operator between an expression of ulong and an expression of ulong?, then the operator overload bool ulong(ulong left, ulong right) appears to be used.
In other words, the operator considers both expressions non-null.
In this sample program, equal correctly becomes false, with no exceptions.
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;
}
}
- How can this not throw? There is no conversion from a
ulong?with value null to aulong.(ulong)(ulong?)nullthrows: "Nullable object must have a value." - Does this return the correct value for every possible value of
ulong?, including null? If so, how? The typeulong?has one more possible value thanulong, so there should be one set of two values that map to the sameulongvalue, which would introduce one false positive "true" result.
In theory, I could imagine null being coalesced to default(ulong), but then the result in my example above would be true, which would be an incorrect answer. And as we can see, the compiler does not make that mistake - it answers correctly.

From MSDN:
You're not using the operator:
You're using the lifted operator:
This operator takes two
ulong?parameters, and returns true if both are null, or if both are non-null and have the same value.You're probably looking at Visual Studio, which does show you something confusing in this case:
Don't be confused by this -- as @mjwills pointed out in the comments, this is a known issue.
If you write this:
Then the compiler produces the following code:
num.GetValueOrDefault()returns0ifbisnull, otherwise the value ofb. SoMreturnstrueif and only ifbis not null, and has the same value asa.SharpLab