Почему я могу сравнить sbyte со всеми другими числовыми типами * кроме * ulong? - PullRequest
25 голосов
/ 01 декабря 2010

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

Мой мозг взрывается.Может кто-нибудь объяснить, почему 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);
}

Ответы [ 2 ]

20 голосов
/ 02 декабря 2010

Ответы Дторпа и Джона близки, но не совсем верны.

Правильные рассуждения таковы.

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

Для операции вида 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);

Плюс оператор «enum less-than» для всех перечисляемых типов, а также версии каждого из вышеперечисленных с возвратом в нуль.

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

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);

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

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

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

Осталось три.Какой из этих трех лучший?

float более специфичен, чем double.Каждый float конвертируется в double, но не каждый double конвертируется в float.Поэтому двойной исключается.Осталось два.

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

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

Следовательно, нельзя определить лучшего оператора.Не удается разрешить перегрузку.

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

7 голосов
/ 01 декабря 2010

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

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

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

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...