What is the logic of the compiler error (i.e. how did the compiler come to ambiguity)?
First we need to determine which methods are in the method group. Clearly, there are two methods in a group of methods.
Secondly, we must determine which of these two methods is applicable. That is, each argument is implicitly converted to the corresponding parameter type. Obviously, 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 of which has only one parameter, the rule is that the conversion from argument to parameter type of one should be better than the other.
The rules of what makes one conversion better than the other are given in section 7.5.3.5 of the specification, which I quote here for your convenience:
Given the conversion of C1, which is converted from type S to type T1, and the conversion of C2, which is converted from type S to type T2, C1 is a better conversion than C2 if at least one of the following conditions is true: / p>
β’ Identity conversion exists from S to T1, but not from S to T2
β’ T1 is a better conversion target than T2
Given the two different types T1 and T2, T1 is a better conversion goal than T2 if at least one of the following is true:
β’ There is an implicit conversion from T1 to T2 and there is no implicit conversion from T2 to T1
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 a banana is more specific than Fruit.
β’ T1 is a signed integral type, and T2 is an unsigned integral type.
Run the list. Is there an identity conversion from MyDerivedClass to MyCastableClass or MyClass ? No. Is there an implicit conversion from MyClass to MyCastableClass , but not an implicit conversion goes the other way? No. There is no reason to believe that any type is more specific than the other. Are integer types? No.
Therefore, there is no reason to decide that one is better than the other, and therefore it is ambiguous.
Is there something wrong with this design?
The question answers itself. You have found one of the problems.
Intuitively, there should be no ambiguity, and the breaking call should be resolved the first time the method is overloaded, since MyDerivedClass is more closely related to MyClass
Although this may be intuitive for you, the specification does not distinguish in this case between a custom transform and any other implicit transform. However, I note that your distinction is indeed taken into account in some rare cases; see my custom conversion chain article for more details. ( http://blogs.msdn.com/b/ericlippert/archive/2007/04/16/chained-user-defined-explicit-conversions-in-c.aspx )