The relevant section of the C # specification is -
The section is long, but it prefers this: you define the explicit conversion using (Foo)doub
, and since you use the explicit conversion, the compiler will select the most accessible conversions available, including conversions that are explicit, to take intermediate steps along the conversion path (if available).
If U contains exactly one custom conversion operator that converts from SX to TX, then this is the most specific conversion operator. If such an operator does not exist, or if more than one such operator exists, then the conversion is ambiguous and a compile time error occurs. Otherwise, a custom transformation is applied:
If S is not SX, then the standard explicit conversion from S to SX is performed.
To convert from SX to TX, the most specific user conversion operator is called.
If TX is not T, a standard explicit conversion from TX to T is performed.
(my emphasis)
Here S
is the source type and T
is the destination type, and SX
is the most specific source type defined in explicit destination type operators (i.e. Foo
) and TX
is the most specific destination type defined in explicit T
operators.
Here, an explicit conversion exists from double
to int
, and therefore it is selected as the most suitable for conversion from the type of the original argument ( double -- S
) to the type of the input argument of the explicit operator ( int -- SX
). It does not have to be explicit, since you have already explicitly pointed to the conversion to Foo
.
This only works because there are no ambiguous alternatives. If you defined Foo
to have:
struct Foo { public int value; public uint uvalue; public static explicit operator Foo(int val) { return new Foo { value = val }; } public static explicit operator Foo(uint val) { return new Foo { uvalue = val }; } }
for example, this leads to a compile-time error (with the same Main
):
Error 1 Ambiguous user conversions "Foo.explicit operator Foo (uint)" and "Foo.explicit operator Foo (int)" when converting from "double" to "Foo"
Again, this is from the book (in the first paragraph above), since the set of available conversions U
now contains two equally valid explicit conversions, and the compiler cannot decide whether you intend to use the int
transform or the uint
transform. In the inital example, there is only one choice, and this is understandable, so the compiler takes it.