#c# #implicit-conversion #ambiguous-call
Вопрос:
У меня есть несколько классов C#, MyChar, Myint, myDouble, которые переносят символы char, int и double. У каждого есть неявный оператор преобразования из обернутого типа в определенный пользователем. У меня также есть набор перегруженных функций, toString(MyChar), toString(myInt), toString(myDouble).
Я хочу вызвать toString(MyChar), передав буквальное значение символа, например «A». Но компиляция завершается неудачно с CS0121, «Вызов неоднозначен между следующими методами или свойствами:» toString(MyChar)» и «toString(myInt)»». И у меня возникает аналогичная проблема, если я передаю значение int.
public class MyChar
{
private MyChar(char val) => Value = val;
public static implicit operator MyChar(char val) => new MyChar(val);
public char Value { get; }
}
public class MyInt
{
private MyInt(int val) => Value = val;
public static implicit operator MyInt(int val) => new MyInt(val);
public int Value { get; }
}
public class MyDouble
{
private MyDouble(double val) => Value = val;
public static implicit operator MyDouble(double val) => new MyDouble(val);
public double Value { get; }
}
public class ConversionTests
{
public void DoIt()
{
Console.WriteLine(ToString('A')); // CS0121
Console.WriteLine(ToString(1)); // CS0121
}
private static string ToString(MyChar c) => $"{c.Value}";
private static string ToString(MyInt i) => $"{i.Value}";
private static string ToString(MyDouble d) => $"{d.Value}";
}
Я обнаружил, что могу заставить компилятор правильно принимать значение int, добавив неявное преобразование из myInt в myDouble
public class MyDouble
{
private MyDouble(double val) => Value = val;
public static implicit operator MyDouble(double val) => new MyDouble(val);
public static implicit operator MyDouble(MyInt val) => new MyDouble(val.Value);
public double Value { get; }
}
...
public void DoIt()
{
Console.WriteLine(ToString('A')); // CS0121
Console.WriteLine(ToString(1)); // now compiles :-)
}
Я предполагаю, что это работает, потому что механизм разрешения теперь считает, что преобразование в myDouble теперь выполняется по маршруту 1 -> myInt ->> myDouble, и это не может произойти неявно, поскольку для этого требуется два пользовательских преобразования. В том же духе я могу ToString('A')
решить проблему правильно, добавив еще два неявных преобразования: MyChar в myDouble и MyChar в myInt.
Это нормально, так как оно отражает неявные преобразования, которые происходят между символами char, int и double. Но может ли кто-нибудь объяснить мне, почему исходный код, опубликованный выше, не будет компилироваться без дополнительных преобразований так, как мог бы понять простой мозг, подобный моему?
Комментарии:
1.A
Char
может быть неявно приведено к anInt
. Anint
может быть неявно приведено кdouble
. Учитывая неявные приведения кMy
типам, это означает, чтоToString('A')
это может быть обработано обоимиToString
методами. Вы можете удалить всеToString()
методы, кромеToString(MyInt)
, и код все равно будет работать2. Что ты пытаешься сделать? Вы пробуете что-то или это упрощенный случай реальной проблемы?
3. @PanagiotisKanavos Это самое простое сокращение проблемы, которую я нашел в своем коде. Я хочу представить полный API, поэтому у меня нет роскоши удалять методы. Я хочу использовать перегруженное имя, так как в сознании пользователя операция-это одно и то же, независимо от типа, на котором она выполняется. Чего я не понимаю, так это почему символ преобразования -> MyChar не выбран в качестве однозначного преобразования, поскольку он ближе, чем символ ->> int ->>> myInt.
4. опишите реальную проблему в самом вопросе. Ни одно из преобразований не находится ближе, чем другое. Все они требуют неявных приведений, поэтому ни одно из них не ближе другого. Для этих примеров существует несколько методов, которые могут быть вызваны после неявных приведений.
5.
as in the user's mind the operation is the same thing, irrespective of the type its operating on.
почему бы тогда не использовать общий метод? Приведите пример реальной проблемы. Вы можете использовать общий интерфейс для всех типов, использовать общие методы или использовать какой-либо другой трюк
Ответ №1:
A char
может быть неявно приведено к an int
. An int
может быть неявно приведено к double
. Учитывая неявные приведения к My
типам, это означает, что ToString('A')
это может быть обработано обоими ToString
методами.
Вы можете удалить все ToString()
методы, кроме ToString(MyInt)
, и код все равно будет работать:
public class ConversionTests
{
public void DoIt()
{
Console.WriteLine(ToString('A'));
Console.WriteLine(ToString(1));
}
private static string ToString(MyInt i) => $"{i.Value}";
}
Это напечатало бы :
65
1