Given the following, why does the InvalidCastException get thrown? I can\'t see why it should be outside of a bug (this is in x86; x64 crashes with a 0xC0000005 in clrjit.dll).<
It is clearly a C# compiler bug. Thanks for bringing it to my attention.
Incidentally, it is a bad practice to have a user defined implicit conversion operator that throws an exception; the documentation states that implicit conversions should be those that never throw. Are you sure you don't want this to be an explicit conversion?
Anyway, back to the bug.
The bug repros in C# 3 and 4 but not in C# 2. Which means that it was my fault. I probably caused the bug when I redid the user-defined lifted implicit operator code in order to make it work with expression tree lambdas. Sorry about that! That code is very tricky, and apparently I did not test it adequately.
What the code is supposed to do is:
First, overload resolution attempts to resolve the meaning of ==. The best == operator for which both arguments are valid is the lifted operator that compares two nullable doubles. Therefore it should be analyzed as:
Boolean compare = (double?)my == (double?)0.0;
(If you write the code like this then it does the right thing in C# 3 and 4.)
The meaning of the lifted == operator is:
Now the question is "what is the right way to evaluate the left hand side?"
We have here a lifted user-defined conversion operator from MyDouble? to double?. The correct behaviour is:
Clearly something is going wrong in this process.
I'll enter a bug in our database, but any fix will probably miss the deadline for changes that make it into the next service pack. I would be looking into workarounds if I were you. Again, apologies for the error.
This sure looks like a compiler bug to me. The IL suggests the compiler is generating code to convert the MyDouble? to a double with the conversion operator, then to a double?. But takes a nosedive when it then uses the conversion operator again on that double?. That's bad, wrong argument type. Nor is there a need.
This feedback article resembles this bug. Over 6 years old already, that must be a tricky part of the compiler. I do imagine it is.