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;
}
}
ulong?
with value null to a ulong
. (ulong)(ulong?)null
throws: "Nullable object must have a value."ulong?
, including null? If so, how? The type ulong?
has one more possible value than ulong
, so there should be one set of two values that map to the same ulong
value, 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:
Lifted operators permit predefined and user-defined operators that operate on non-nullable value types to also be used with nullable forms of those types. Lifted operators are constructed from predefined and user-defined operators that meet certain requirements, as described in the following:
...
For the equality operators
== !=
a lifted form of an operator exists if the operand types are both non-nullable value types and if the result type is
bool
. The lifted form is constructed by adding a single?
modifier to each operand type. The lifted operator considers two null values equal, and a null value unequal to any non-null value. If both operands are non-null, the lifted operator unwraps the operands and applies the underlying operator to produce thebool
result.
You're not using the operator:
bool ==(ulong left, ulong right)
You're using the lifted operator:
bool ==(ulong? left, ulong? right)
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:
public bool M(ulong a, ulong? b) {
return a == b;
}
Then the compiler produces the following code:
public bool M(ulong a, ulong? b)
{
ulong? num = b;
return (a == num.GetValueOrDefault()) & num.HasValue;
}
num.GetValueOrDefault()
returns 0
if b
is null
, otherwise the value of b
. So M
returns true
if and only if b
is not null, and has the same value as a
.
SharpLab
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) is used.
A large part of the issue is that Visual Studio's intellisense incorrectly shows ulong
's ==
operator being used (if you hover over ==
).
This is a bug, as per https://github.com/dotnet/roslyn/issues/21494 . It is not actually using that operator.
Since all of your other questions are based on that faulty premise, realising the existence of that bug makes the other issues largely disappear.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With