As an extension to Stefan's excellent answer - another exception is if the operands involve Nullable<T>
- in which case "lifted" operators apply (14.2.7 in ECMA 334v4):
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.
What that means is: because there is an equality operator between (say):
int i = ..., j = ...;
bool eq = i == j;
Thus there is an implicit operator of the form (although done differently):
int? i = ..., j = ...;
bool eq;
if(i.HasValue) {
if(j.HasValue) { // both have values; compare
eq = i.GetValueOrDefault() == j.GetValueOrDefault();
} else { // one null; always false
eq = false;
}
} else { // true if both null, else false
eq = !j.HasValue;
}