c# работает Почему я могу сравнить sbyte со всеми другими числовыми типами*кроме*ulong?




как работает clr (2)

Вы можете делать>, <, == и т. Д. Сравнения между sbyte и byte, int, uint, short, ushort, long, double и float. Но не улонг.

Мой мозг взрывается. Может ли кто-нибудь объяснить, почему сбайт можно сравнить с uint, но не улунгом?

public bool sbyte_ulong_compare(sbyte x, ulong y)
{
    return x < y;  // compiler error CS0019
}

Кроме того, использование unchecked не улучшает работу. Плавление головного мозга.

Другое редактирование. Это работает:

public bool sbyte_ulong_compare(sbyte x, ulong y)
{   
    //
    // returns x < y
    //
    if (x < 0)
        return true;

    if (y > 127)
        return true;

    return ((long)x < (long)y);
}

Ответы dthorpe и Jon близки, но не совсем корректны.

Правильные рассуждения заключаются в следующем.

В спецификации указано:

Для операции вида x op y, где op является оператором сравнения, для выбора конкретной реализации оператора применяется разрешение перегрузки.

Хорошо, каковы операционные реализации, с которыми приходится работать с перегрузкой? Они есть:

bool operator <(int x, int y);
bool operator <(uint x, uint y);
bool operator <(long x, long y);
bool operator <(ulong x, ulong y);
bool operator <(float x, float y);
bool operator <(double x, double y);
bool operator <(decimal x, decimal y);

Кроме того, оператор перечисления меньше, чем оператор для всех перечисленных типов, плюс версии с отмененными до нуля для каждого из вышеперечисленных.

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

Операторы int, uint, long и enum (и их снятые формы) устраняются, поскольку ulong неявно не преобразуется в эти типы.

Операторы uint и ulong (и их снятые формы) устраняются, потому что sbyte не подразумевает конвертацию в эти типы.

Это оставляет

bool operator <(float x, float y);
bool operator <(double x, double y);
bool operator <(decimal x, decimal y);

и их поднятые формы. Теперь мы должны определить лучший оператор из этих шести.

Что мы понимаем под «лучшим»? При сравнении двух операторов один из них с более конкретными типами операндов является лучшим. Под «более конкретным» я имею в виду, что «Тигр» более специфичен, чем «Животное», потому что все тигры конвертируются в Animal, но не все животные могут быть конвертированы в Tiger.

Очевидно, что незакрепленные формы лучше всех соответствующих поднятых форм. Тип с нулевым значением более конкретный, чем его соответствующий тип с нулевым значением, потому что тип с недействительным значением всегда конвертируется в его тип с нулевым значением, но не наоборот. Мы можем устранить поднятые формы.

Это оставляет три. Какой из этих трех лучших?

float более конкретный, чем двойной. Каждый float конвертируется в double, но не каждый двойной конвертируется в float. Поэтому double устраняется. Это оставляет два.

bool operator <(float x, float y);
bool operator <(decimal x, decimal y);

Какой из них лучше? Нет никакого неявного преобразования от float до десятичного. Нет никакого неявного преобразования из десятичного числа в float. Поэтому ни один не лучше другого.

Поэтому лучший оператор не может быть определен. Ошибка перегрузки.

Мы решили сообщить об общем сообщении об ошибке, которое просто говорит, что такого оператора нет, который делает то, что вы хотите, вместо того, чтобы давать кажущееся странным и запутанным сообщение об ошибке «ошибка перегрузки оператора не удалась, потому что float не лучше и не хуже десятичного». Я думаю, что это разумный выбор дизайна.


Когда вы сравниваете два целых числа целочисленных типов, тип операции представляет собой наименьший целочисленный тип, который может представлять полный диапазон обоих операндов в сочетании. Если вы сравниваете подписанный байт с uint, тип операции длинный, потому что long имеет достаточный диапазон для покрытия отрицательной части подписанного байта и положительной части uint.

Когда вы пытаетесь сравнить sbyte и ulong, нет целочисленного типа, который может охватывать диапазоны как ulong, так и отрицательной части подписанного байта. Компилятор учитывает только встроенные целочисленные типы. Неявно продвижение в десятичное не включено, потому что Decimal не является целым типом и по соображениям производительности.

В примере 2-го кода, поскольку вы предварительно подготовили операнды, вы можете безопасно вывести операнды в общий тип целочисленного типа, который не охватывает диапазон обоих операндов. Обратите также внимание на то, что во втором примере вы можете прибегать к байту (вместо длинного) без потери информации, так как вы уже установили, что значение ulong меньше 127, а значение sbyte неотрицательно.

Компилятор C # не «видит», что вы предварительно квалифицировали операнды, и что логически значения в операндах находятся в пределах байтового диапазона, а компилятор не генерирует код для выполнения таких предварительных квалификаций.

Некоторые языки испускают предквалификационный код, аналогичный вашему 2-му примеру, чтобы поддерживать сравнения между типами, которые не имеют общего типа надмножества. Для этого вы используете производительность и память (размер кода). C #, вероятно, не испускает такой предквалификационный код в духе нежелания «вознаграждать» за плохое кодирование. Если вы сравниваете знаковое значение и ulong, вам нужно знать и брать на себя ответственность за расходы.

В теории языка существует ветвь типа inferencing, называемая (я думаю), типа алгебра, которая отслеживает тесты против переменных и динамически сужает диапазон типа переменной, поскольку в потоке кода обнаруживаются новые ограничения. Эта форма ввода типов позволит вам сравнить операнды без приведения типов в ваш второй пример, потому что он увидит, что вы предварительно квалифицировали операнды в диапазоне байтов. C # не делает такого типа вывода. Я думаю, что Haskell или F # могут.





clr