Patrick Skelton Ответов: 3

Почему тернарный оператор C#, по - видимому, изменяет тип возвращаемых значений?


У меня есть следующее if() заявление:

if( _hexColourString.Length >= 8 )
    _bytes[ 3 ] = byte.Parse( _hexColourString.Substring( start + 6, 2 ), NumberStyles.AllowHexSpecifier );
else
    _bytes[ 3 ] = 0x00;


Если я попытаюсь выразить это с помощью тернарного оператора, то получу ошибку, говорящую о том, что я не могу неявно преобразовать int К byte Следующее не компилируется:

_bytes[ 3 ] = ( _hexColourString.Length >= 8 ) ? byte.Parse( _hexColourString.Substring( start + 6, 2 ), NumberStyles.AllowHexSpecifier ) : 0x00;


Поэтому я решил проверить, какая половина троичного задания дает проблему. Я вынул условную часть утверждения и записал два задания как отдельные утверждения, например::

_bytes[ 3 ] = byte.Parse( _hexColourString.Substring( start + 6, 2 ), NumberStyles.AllowHexSpecifier );
_bytes[ 3 ] = 0x00;


Оба они компилируются. Тернарный оператор, по-видимому, изменяет неявный тип одного из назначений (литерала 0x00).

Почему происходит простое назначение _bytes[ 3 ] = 0x00; компилировать нормально без приведения, но требует его, когда выражение является частью тернарного оператора?

Что я уже пробовал:

В качестве последней проверки здравомыслия я хотел окончательно понять, какая сторона задания была причиной проблемы. Я подозревал, что буквальный шестнадцатеричный байт, и, похоже, я прав. Следующее бессмысленное утверждение компилируется:

_bytes[ 3 ] = ( _hexColourString.Length >= 8 ) ? byte.Parse( _hexColourString.Substring( start + 6, 2 ), NumberStyles.AllowHexSpecifier ) :
                byte.Parse( _hexColourString.Substring( start + 6, 2 ), NumberStyles.AllowHexSpecifier );


Но следующее столь же бессмысленное утверждение не компилируется:

_bytes[ 3 ] = ( _hexColourString.Length >= 8 ) ? 0x00 : 0x00;

CHill60

Потому что 0x00-это int, а не байт, возможно?

Patrick Skelton

Конечно, вы правы. Я думаю, что мой вопрос действительно должен был бы состоять в том, почему простое присваивание (_bytes[ 3 ] = 0x00;) компилируется нормально без приведения, но требует его, когда выражение является частью тернарного оператора?

CHill60

Обычно я бы сказал, что было неявное преобразование, но нет никакого неявного преобразования из int в byte. Компилятор должен обнаружить, что 0x00 как константа меньше байта и не вызовет переполнения - кто знал, что MS может быть настолько умной? :-)

Patrice T

И компилятор вам что-то говорит ?

Patrick Skelton

Извините, я не уверен, что понял вопрос. Когда я использую 0x00 в тернарном операторе, компилятор действительно говорит мне, что я не могу преобразовать int в байт, что является однозначной, краткой формулировкой проблемы. Я попытался прояснить свой вопрос.

3 Ответов

Рейтинг:
9

CHill60

В дополнение к двум другим решениям (и комментариям) Я нашел это довольно хорошее объяснение у Эрика Липперта ... Почему я должен относиться к типу int в троичное выражение?[^]


Patrick Skelton

Это действительно отличное объяснение, хорошо использующее прямые цитаты из спецификации языка. Спасибо!

Рейтинг:
21

F-ES Sitecore

Попробуйте просто "0"

_bytes[ 3 ] = ( _hexColourString.Length >= 8 ) ? byte.Parse( _hexColourString.Substring( start + 6, 2 ), NumberStyles.AllowHexSpecifier ) : 0;


Или явный актерский состав

_bytes[ 3 ] = ( _hexColourString.Length >= 8 ) ? byte.Parse( _hexColourString.Substring( start + 6, 2 ), NumberStyles.AllowHexSpecifier ) : (byte)0;


Patrick Skelton

Ваш код исправляет мою проблему, но я отметил другой ответ как решение, потому что он предлагает объяснение, которое должно помочь любому другому, кто наткнется на эту тему.

На самом деле я, вероятно, буду использовать явный бросок, о котором вы упомянули выше, просто чтобы сказать кому-то еще, читающему мой код, что я не ошибся.

Рейтинг:
19

OriginalGriff

Цитата:
Я думаю, что мой вопрос действительно должен был бы состоять в том, почему простое присваивание (_bytes[ 3 ] = 0x00;) компилируется нормально без приведения, но требует его, когда выражение является частью тернарного оператора?

Потому что компилятор может сказать из контекста, что значение константы должно быть байтом, а не int.
Однако при создании тернарной операции у компилятора есть выбор:
byte b = 100;
byte c = (a ? b : 0)
Это можно было увидеть двумя способами:
byte b = 100;
byte c = (a ? b : (byte) 0)
Или
byte b = 100;
byte c = (a ? (int) b : 0)
И он выберет второе, потому что целые числа являются более распространенной и "естественной" единицей.

Затем он жалуется, потому что неявное приведение от int к необходимому байту потенциально может выбросить информацию. (Не то чтобы там было что выбрасывать, но эй - компиляторы не могут думать обо всем!)


Patrick Skelton

Отличное объяснение, сэр! Спасибо!

OriginalGriff

Всегда пожалуйста!