Оператор ">" не может применяться для типа "ulong" и "int"

Мне любопытно узнать, почему компилятор С# только дает мне сообщение об ошибке для второго оператора if.

enum Permissions : ulong
{
    ViewListItems = 1L,
}

public void Method()
{
    int mask = 138612833;
    int compare = 32;

    if (mask > 0 & (ulong)Permissions.ViewListItems > 32)
    {
        //Works
    }

    if (mask > 0 & (ulong)Permissions.ViewListItems > compare)
    {
        //Operator '>' cannot be applied to operands of type 'ulong' and 'int'
    }
}

Ответ 1

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

Очевидно, что в вашем втором случае это ошибка - вы не можете сравнить ulong и int, потому что не существует типа, с которым вы можете принуждать обоих. A ulong может быть слишком большим для long, а int может быть отрицательным.

В вашем первом случае, однако, компилятор умный. Он понимает, что const 1 > const 32 никогда не является истинным и не включает ваш оператор if в скомпилированный вывод вообще. (Это должно дать предупреждение для недостижимого кода.) То же самое, если вы определяете и используете const int, а не литерал, или даже если вы произвольно написали литерал (т.е. (int)32).

Но разве компилятор успешно не сравнивает ulong с int, который мы только что сказали, что это невозможно?

По-видимому, нет. Итак, что происходит?

Попробуйте вместо этого сделать что-то в следующих строках. (Выполнение ввода и записи, поэтому компилятор ничего не компилирует.)

const int thirtytwo = 32;
static void Main(string[] args)
{
    ulong x = ulong.Parse(Console.ReadLine());
    bool gt = x > thirtytwo;
    Console.WriteLine(gt);
}

Это будет скомпилировано, хотя ulong является переменной, и даже если результат не известен во время компиляции. Взгляните на вывод в ILSpy:

private static void Main(string[] args)
{
    ulong x = ulong.Parse(Console.ReadLine());
    bool gt = x > 32uL;        /* Oh look, a ulong. */
    Console.WriteLine(gt);
}

Итак, компилятор фактически обрабатывает ваш const int как ulong. Если вы сделаете thirtytwo = -1, код не скомпилируется, хотя мы знаем, что gt всегда будет true. Сам компилятор не может сравнивать ulong с int.

Также обратите внимание, что если вы создаете x a long вместо ulong, компилятор генерирует 32L, а не 32 как целое число, даже если это не обязательно. (Вы можете сравнить int и a long во время выполнения.)

Это указывает на то, что компилятор не обрабатывает 32 как ulong в первом случае, потому что он должен, просто потому, что он может соответствовать типу x. Это экономит время выполнения от принуждения константы, и это просто бонус, когда принуждение по правам не может быть возможным.

Ответ 2

Это не CLR, дающее этому сообщению об ошибке компилятор.

В первом примере компилятор рассматривает 32 как ulong (или тип, который неявно конвертируется в ulong, например uint), тогда как во втором примере вы явно объявили тип как int, Не существует перегрузки оператора >, который принимает ulong и int, и, следовательно, вы получаете ошибку компилятора.

Ответ 3

rich.okelly и rawling отвечают правильно, почему вы не можете сравнивать их напрямую. Вы можете использовать Convert класс ToUInt64 для продвижения int.

if (mask > 0 & (ulong)Permissions.ViewListItems > Convert.ToUInt64(compare))
{
}