Предположим, есть два класса со следующим неявным и явным шаблоном оператора:
class Foo
{
public static implicit operator decimal (Foo foo)
{
throw new NotImplementedException();
}
public static implicit operator Foo (decimal value)
{
throw new NotImplementedException();
}
public static Foo operator +(Foo left, Foo right)
{
throw new NotImplementedException();
}
}
class Bar
{
public static explicit operator decimal (Bar bar)
{
throw new NotImplementedException();
}
public static explicit operator Foo(Bar bar)
{
throw new NotImplementedException();
}
}
Теперь рассмотрим следующий код:
var foo = new Foo();
var bar = new Bar();
var resultFooAddBar = foo + (decimal)bar;
Неявно введенный resutlFooAddBar
разрешается в Foo
, а оператор добавления разрешается в Foo Foo.operator +
. Почему этот код не выдает неоднозначную ошибку? Оператор мог бы также разрешить decimal decimal.operator +
. Это потому, что определяемые пользователем операторы всегда считаются более подходящими? Тем не менее, выбор кажется немного странным, учитывая, что Bar
имеет явное приведение к Foo
, которое не использовалось, что явно определяет, какой оператор хотел бы использовать программист:
var resultFooAddBar = foo + (Foo)bar;
//Хорошо, я прямо говорю, что хочу Foo Foo.operator +
Если вместо decimal
мы используем третий класс Tango
, определяющий Tango Tango.operator + (Tango, Tango)
, и те же неявные и явные шаблоны операторов, то компилятор выдает ошибку неоднозначного вызова.
Почему такое различие между операторами, определяемыми пользователем, и операторами, не определяемыми пользователем?
ОБНОВЛЕНИЕ: я создал отдельную сборку, включающую следующий класс, чтобы проверить объяснение Servy:
namespace ExternalAssembly
{
public class Tango
{
public static Tango operator +(Tango left, Tango right)
{
throw new NotImplementedException();
}
}
}
А затем изменил decimal
на Tango
в Foo
и Bar
и добавил необходимую ссылку на dll ExternalAssembly. В этом случае я все еще получаю, что оператор '+' неоднозначен для операндов 'ConsoleApplication.Foo' и 'ExternalAssembly.Tango'. Почему бы компилятору в этом случае не выбрать ту же перегрузку Foo Foo.operator +
, что и в моем первоначальном вопросе с decimal
?
decimal
+decimal
. Существует неявное преобразование изFoo
вdecimal
, но вместо этого компилятор выбирает неявное преобразование изdecimal
вFoo
. См. последний абзац (только что отредактированный). - person InBetween   schedule 18.09.2014