Разрешение перегрузки при применении оператора | к перечислениям различных типов

После прочтения недавнего вопроса Операции между различными типами перечислений разрешены в другом объявлении перечисления, но не в другом месте. Я придумал этот пример. :

    enum Alpha : long
    {
        X,
    }

    enum Beta : ulong
    {
        X,
    }

    enum Gamma : long
    {
        X = Alpha.X | Beta.X,   // problem?
    }

    enum Delta : ulong
    {
        X = Alpha.X | Beta.X,   // no problem?
    }

Результат компиляции: Gamma не компилируется (CS0266: Невозможно неявно преобразовать тип 'ulong' в 'long'. Существует явное преобразование (вам не хватает приведения?)). Delta успешно компилируется.

Разве этого не следует ожидать от Спецификации языка C#?

(Примечание: если я изменю член Alpha, чтобы он был инициализирован отрицательной константой, такой как -1L, то ни Gamma, ни Delta не будут компилироваться.)


person Jeppe Stig Nielsen    schedule 27.01.2013    source источник
comment
planetgeek.ch/2009/07/01/enums-are-evil   -  person Richard Schneider    schedule 27.01.2013


Ответы (2)


Да, это ожидаемо, и это не что-то специфичное для перечисления. Вы можете упростить его до:

long a = 1L | 1UL; // Cannot implicitly convert type 'ulong' to 'long'. An explicit conversion exists (are you missing a cast?)
ulong b = 1L | 1UL;

Следующие цитаты из Спецификации языка C# объясняют, почему это происходит.

6.1.9 Преобразование неявных константных выражений

Преобразование неявного константного выражения допускает следующие преобразования:

· Константное-выражение (§7.19) типа int может быть преобразовано в тип sbyte, byte, short, ushort, uint или ulong при условии, что значение константного-выражения находится в пределах диапазона целевого типа.

· Константное выражение типа long может быть преобразовано в тип ulong при условии, что значение константного выражения не является отрицательным.

6.1.2 Неявные числовые преобразования

Неявные числовые преобразования:

· От длинного до плавающего, двойного или десятичного числа.

· От ulong до float, double или decimal.

Другими словами, Alpha.X (если базовое значение положительно) может быть (на самом деле так и есть!) неявно преобразовано в ulong. Но результатом Alpha.X | Beta.X является ulong, который, согласно спецификациям, не может быть неявно преобразован в long.

Но как только вы измените Alpha.X для инициализации отрицательной константой, такой как -1L, тогда, согласно приведенной выше цитате, его больше нельзя будет неявно преобразовать в ulong, и компиляция завершится ошибкой с другой ошибкой: Operator '|' cannot be applied to operands of type 'long' and 'ulong'

person Nikolay Khil    schedule 27.01.2013
comment
А, теперь я вижу это. Таким образом, для постоянных выражений существует больше неявных преобразований, чем для непостоянных выражений. В частности, существует неявное преобразование из long в ulong (для константных выражений), но не наоборот. Объясняет это. - person Jeppe Stig Nielsen; 27.01.2013

Да, это ожидаемо, неявного преобразования ulong в какой-либо целочисленный тип нет.

Как только вы сообщаете компилятору, что long is -ve, вы даете ему достаточно информации, чтобы сказать, что вы не хотите этого делать.

Лично я был бы рад, если бы он расстроился из-за долгого | ulong, но, несомненно, некоторые программисты на C повлияли на это решение. :(

person Tony Hopkinson    schedule 27.01.2013
comment
Также нет неявного преобразования long в какой-либо целочисленный тип, поэтому можно было бы подумать, что он симметричен. Тем не менее, это работает для Delta, но не для Gamma. Нулевое значение находится в диапазоне как для long, так и для ulong (снова симметрично), так откуда берется асимметрия? - person Jeppe Stig Nielsen; 27.01.2013
comment
Я думаю, что они ошиблись и в этом, но не из-за симметрии. Они рассматривали это как байт в слово и слово в байт. +ve long к ulong безопасен, потому что вы не теряете информацию. - person Tony Hopkinson; 27.01.2013