Подтвердить что ты не робот

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

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

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

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);
}
4b9b3361

Ответ 1

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 не лучше и не хуже десятичная дробь". Я думаю, что это разумный выбор дизайна.

Ответ 2

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

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

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

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

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

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