1

Based on this question, I (and OP in said question) got confused, when this piece of code compiles and runs :

DateTime dateTime = new DateTime();
bool isFalse = dateTime == null;
bool isTrue  = dateTime != null;

Notice that the dateTime variable is not nullable. When I hover over the equality sign, it tells me it is's signature is bool DateTime.operator==(DateTime dateTime1, DateTime dateTime2) and the null is of Nullable<DateTime>.

What is compiler doing here? Is it using some kind of implicit conversion?

I have found similar question here, but it just shrugs away the problem and doesn't explain why compiler is doing this.

Euphoric
  • 12,645
  • 1
  • 30
  • 44

1 Answers1

1

According to the rules for Binary operator overload resolution:

An operation of the form x op y, where op is an overloadable binary operator, x is an expression of type X, and y is an expression of type Y, is processed as follows:

  • The set of candidate user-defined operators provided by X and Y for the operation operator op(x,y) is determined. The set consists of the union of the candidate operators provided by X and the candidate operators provided by Y, each determined using the rules of Candidate user-defined operators. [...]

Candidate user-defined operators says:

For all operator op declarations in T0 and all lifted forms of such operators, if at least one operator is applicable with respect to the argument list A, then the set of candidate operators consists of all such applicable operators in T0.

Lifted operators:

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 the bool result.

So the compiler looks at the operands DateTime and null, finds the user-defined ==(DateTime, DateTime) operator, and lifts it to ==(DateTime?, DateTime?). As both DateTime and null can be implicitly converted to DateTime?, this lifted operator is applicable and ultimately selected as the best candidate.

Community
  • 1
  • 1
kalimag
  • 1,139
  • 2
  • 6
  • 11