What it the logic behind the compiler error (i.e. how did the compiler arrive to an ambiguity)?
First we must determine what methods are in the method group. Clearly there are two methods in the method group.
Second, we must determine which of those two methods are applicable. That is, every argument is convertible implicitly to the corresponding parameter type. Clearly both methods are applicable.
Third, given that there is more than one applicable method, a unique best method must be determined. In the case where there are only two methods each with only one parameter, the rule is that the conversion from the argument to the parameter type of one must be better than to the other.
The rules for what makes one conversion better than another is in section 7.5.3.5 of the specification, which I quote here for your convenience:
Given a conversion C1 that converts from a type S to a type T1, and a conversion C2 that converts from a type S to a type T2, C1 is a better conversion than C2 if at least one of the following holds:
? An identity conversion exists from S to T1 but not from S to T2
? T1 is a better conversion target than T2
Given two different types T1 and T2, T1 is a better conversion target than T2 if at least one of the following holds:
? An implicit conversion from T1 to T2 exists, and no implicit conversion from T2 to T1 exists
The purpose of this rule is to determine which type is more specific. If every Banana is a Fruit but not every Fruit is a Banana, then Banana is more specific than Fruit.
? T1 is a signed integral type and T2 is an unsigned integral type.
Run down the list. Is there an identity conversion from MyDerivedClass
to either MyCastableClass
or MyClass
? No. Is there an implicit conversion from MyClass
to MyCastableClass
but not an implicit conversion going the other way? No. There is no reason to suppose that either type is more specific than the other. Are either integral types? No.
Therefore there is nothing upon which to base the decision that one is better than the other, and therefore this is ambiguous.
Is there anything wrong with this design?
The question answers itself. You've found one of the problems.
Intuitively there should be no ambiguity and the offending call should be resolved in the first method overload as MyDerivedClass is more closely related to MyClass
Though that might be intuitive to you, the spec does not make a distinction in this case between a user-defined conversion and any other implicit conversion. However I note that your distiction does count in some rare cases; see my article for details. (Chained user-defined explicit conversions in C#)