Here is quote from specification about that (section 7.10.6 Reference type equality operators). This section is about predefined object equality operators (== (object x, object y)
) which are used in this case:
The predefined reference type equality operators require one of the
following:
• Both operands are a value of a type known to be a
reference-type or the literal null. Furthermore, an explicit reference
conversion (§6.2.4) exists from the type of either operand to the type
of the other operand.
• One operand is a value of type T where T is a
type-parameter and the other operand is the literal null. Furthermore
T does not have the value type constraint.
And from section 6.2.4 we may find that:
The explicit reference conversions are:
• From any class-type S to any interface-type T, provided S is not
sealed and provided S does not implement T.
Because of that
var test = new MyType() == (IEnumerable<MyType>)myCollection;
works, because there is explicit reference conversion from MyType
to IEnumerable<MyType>
as per above. However, if you make MyType
sealed - then there will be no such conversion and that will not compile. The same will happen if you use some predefined sealed type, such as string
(I mean - it will not compile).
The reason explicit reference conversion is allowed for non-sealed type to any interface is because runtime type of that variable can be any of the child classes, and that child class might implement that interface. Sealed classes cannot be inherited, so compiler can be sure that is not the case.