Допускается использование нескольких явных системных преобразователей, но явных преобразователей для нескольких пользователей - нет. Зачем?
Если у меня есть этот код, он скомпилируется и будет работать как следует:
class MyNumber // Just a class.
{
static public explicit operator MyNumber(byte b)
{
return new MyNumber();
}
}
Decimal d = new Decimal();
MyNumber c1 = (MyNumber)d;
Поражение некоторых людей немного удивляет, поскольку не существует явного приведения decimal
в MyNumber
, Но так как есть явное приведение от decimal
в byte
и есть также явное приведение от byte
в MyNumber
, компилятор достаточно любезен, чтобы вставить это дополнительное явное приведение для меня.
Вкратце: если программист использует явное приведение, у компилятора есть свобода поиска другого явного преобразования, чтобы все это работало.
Итак... Я попробовал то же самое на своих занятиях. Вместо byte
а также decimal
, Я использовал MyByte
а также Mydecimal
, Код выглядит так:
class MyDecimal // Simulates a decimal.
{
static public explicit operator MyByte(MyDecimal a) // Just like in a decimal.
{
return new MyByte();
}
}
class MyByte // Simulates a byte.
{
}
class MyNumber // Just a class.
{
static public explicit operator MyNumber(MyByte b)
{
return new MyNumber();
}
}
MyDecimal d = new MyDecimal();
MyNumber c2 = (MyNumber)d; // <== Will not compile!
Последняя строка не скомпилируется. Выдает ошибку: "Невозможно преобразовать тип" DoubleExplicitCasts.Program.MyDecimal "в" DoubleExplicitCasts.Program.MyNumber "". А почему бы не???
Поэтому мой вопрос таков: почему явные операторы внутри системы.NET получают специальную обработку, а мои пользовательские явные операторы - нет?
РЕДАКТИРОВАТЬ
Я знаю, что этот код не работает, и значения не передаются из одного экземпляра в другой, но это не относится к делу.
2 ответа
Ну, тривиально, потому что именно так это определяется стандартом C#.
Из раздела 6.4.3:
Оценка определенного пользователем преобразования никогда не включает в себя более одного определенного пользователем или отмененного оператора преобразования. Другими словами, преобразование из типа S в тип T никогда не выполнит пользовательское преобразование из S в X, а затем выполнит пользовательское преобразование из X в T.
Относительно того, почему они решили ограничить конверсии таким образом, это другой вопрос. Я собираюсь предложить две возможные причины:
- Это позволило бы возможность слишком много "удивительных" конверсий
- Это сделало бы процесс компиляции слишком медленным (возможный комбинационный взрыв)
но это только предположение с моей стороны.
IMO, это привело бы к "счастливой отладке" и действительно, очень сложному и неочевидному коду.
Представьте себе 3 или более уровней таких пользовательских преобразований, и как бы вы искали ошибку, вызванную преобразованием в середине (например, такое преобразование было введено по ошибке или не должно использоваться в такой ситуации).
Слава Богу, такое поведение не поддерживается.