У меня есть структура как это с явным преобразованием для плавания:
struct TwFix32
{
public static explicit operator float(TwFix32 x) { ... }
}
Я могу преобразовать TwFix32 в интервал с единственным явным броском: (int)fix32
Но преобразовать его в десятичное число, я должен использовать два броска: (decimal)(float)fix32
Нет никакого неявного преобразования от плавания или до интервала или до десятичного числа. Почему компилятор позволяет мне опустить промежуточный бросок для плавания, когда я иду в интервал, но не, когда я иду в десятичное число?
Я часто не могу дать удовлетворительный ответ на вопросы «почему».
Причина, по которой компилятор C# демонстрирует такое поведение, заключается в том, что оно (в данном случае, по крайней мере, (*)) правильная реализация спецификации C#.
В разделе 6.4.5 спецификации описывается, как анализируются определяемые пользователем преобразования. Внимательное прочтение этого раздела объяснит, почему явное преобразование в int является законным, а в десятичное — нет.
В частности, соответствующий абзац:
Найдите набор применимых пользовательских и поднятых операторов преобразования, U. Этот набор состоит из определяемых пользователем и поднятых неявных или явных операторов преобразования, объявленных классами или структурами в D, которые преобразуются из типа, охватывающего или охватываемого S, в тип, охватывающий или охватываемый T. Если U пусто, преобразование не определено и возникает ошибка времени компиляции.
В вашем случае S — это TwFix, а T — это int или десятичная дробь. Единственное определяемое пользователем явное преобразование в TwFix возвращает плавающее значение. int охватывается float, но десятичная дробь не охватывается и не охватывает float.Поэтому множество U имеет член в одном случае и пусто в другом. Поэтому один случай приводит к ошибке, как сказано в спецификации, а другой нет.
У меня есть ощущение, что этот ответ не является удовлетворительным. Если нет, можете ли вы перефразировать вопрос так, чтобы в нем не было слова «почему»? Я намного лучше отвечаю на вопросы «что» или «как», чем на вопросы «почему».
(*) Компилятор имеет известные ошибки в коде, который вычисляет, охватывает ли один тип другой, с целью определения того, какие встроенные преобразования имеют значение при анализе семантики конкретного определяемого пользователем преобразования. Во многих случаях мы намеренно не исправляем эти ошибки, потому что это приведет к резкому изменению реального кода без большой пользы. Мне бы очень хотелось вернуться к этому разделу спецификации и переписать его таким образом, чтобы убрать понятие «охватывающий тип»; это немного странно в спецификации. И, как вы обнаружили,он создает эту странность, где float явно преобразуется в десятичное, а десятичное явно преобразуется в float, но поскольку ни один из них не охватывает другой, определяемый пользователем код явного преобразования не нравится. Однако это очень низкий приоритет.