Интересно о C#: Операторы приведения не подчиняются дистрибутивному закону

четверг, 27 мая 2010, Александр Краковецкий

Эрик Липперт отвечает на вопрос, заданный на StackOverflow, по поводу оператора "?" и приведения типов.

Рассмотрим следующую ситуацию:

object result;
bool isDecimal = GetAmount(out result);
decimal amount = (decimal)(isDecimal ? result : 0);

Разработчик был глубоко удивлен, когда увидел, что данный код компилируется, но потом выдает ошибку приведения (invalid cast exception).

Кто-нибудь видит в чем причина?

В алгебре операция умножения более приоритетная чем операция сложения. Т.е. q * (r + s) - то же самое, что и q*r + q*s. Разработчик ожидал, что операция приведения более приоритетная, чем оператор условия. Это не то же самое, что

decimal amount = isDecimal ? (decimal)result : (decimal)0;

или даже лучше:

decimal amount = isDecimal ? (decimal)result : 0.0m;

Причина в том, что типы условного выражения должны быть согласованными для обеих частей. Правила языка не позволяют возвращать object в одной ветке и int в другой.

В нашем примере мы имеем типы object и int. В то время когда int может быть приведен к типу object, обратное утверждение не верно. Поэтому компилятор выбрал object, что эквивалентно коду:

decimal amount = (decimal)(isDecimal ? result : (object)0);

В нашем случае ноль возвращается как boxed int. Дальше boxed int приводится к decimal, а так как такое приведение не разрешено, мы получаем invalid cast exception.

Источник: Эрик Липперт


Ищите нас в интернетах!

Комментарии

Свежие вакансии