С# приводит объект типа int к нулевому перечислению

Мне просто нужно иметь возможность привести объект к нулевому перечислению. Объект может быть enum, null или int. Спасибо!

public enum MyEnum { A, B }
void Put(object value)
{
    System.Nullable<Myenum> val = (System.Nullable<MyEnum>)value;
}

Put(null);     // works
Put(Myenum.B); // works
Put(1);        // Invalid cast exception!!

person dlsou    schedule 04.03.2011    source источник
comment
Вы избавите себя от некоторых проблем, если будете использовать строго типизированные объявления. Если вы знаете, что Put ожидает Nullable<MyEnum>, почему вы объявляете это object?   -  person Ilya Kogan    schedule 05.03.2011
comment
@Илья Коган, это упрощенная версия функции Put, она работает с другими типами данных, а не только с перечислением.   -  person dlsou    schedule 05.03.2011


Ответы (4)


Как насчет:

MyEnum? val = value == null ? (MyEnum?) null : (MyEnum) value;

Преобразование из упакованного int в MyEnum (если value не равно NULL), а затем использование неявного преобразования из MyEnum в Nullable<MyEnum>.

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

Я считаю, что на самом деле это преобразование, которое не гарантирует работу по спецификации C#, но гарантирует работу по спецификации CLI. Так что, пока вы запускаете свой код C # в реализации CLI (которой вы будете :), все будет в порядке.

person Jon Skeet    schedule 04.03.2011
comment
+1 Клянусь, я ежедневно руководствуюсь ответом Джона Скита на StackOverflow. Молодец, сэр. - person JustinMichaels; 16.04.2013
comment
Более короткий путь: MyEnum? val = (MyEnum?) value ?? null - person Aesir; 25.10.2017
comment
Как насчет: MyEnum? val = value as MyEnum; - person mikev2; 31.01.2018
comment
@mikev2: Это определенно отличается от моего кода на том основании, что он просто вернет ноль, если value не является ни int, ни MyEnum. Однако трудно понять, хотел ли этого ОП или нет. (Вам также понадобится value as MyEnum?;, а не value as MyEnum.) - person Jon Skeet; 31.01.2018
comment
@mikev2: Кроме того, value as MyEnum? возвращает null, когда value является целым числом в штучной упаковке, в отличие от моей версии. - person Jon Skeet; 31.01.2018
comment
Я думаю понимаю -› это действительно работает, как я и предполагал, когда имеешь дело с объектом, содержащим int. (с поправкой as MyEnum?) - person mikev2; 31.01.2018
comment
@mikev2: Нет, даже тогда это не работает - value as MyEnum? возвращает null для упакованного int, тогда как OP хочет, чтобы в этом случае он возвращал ненулевое значение MyEnum?. - person Jon Skeet; 31.01.2018
comment
Я только что попробовал это во всех отношениях, и это совершенно совершенно не работает, когда вы начинаете с чего-то, что еще не является перечислением (и тогда бессмысленно). Спасибо, что поставили меня прямо! - person mikev2; 31.01.2018
comment
@mikev2: Вы имеете в виду использование as? Да, в самом деле. Принимая во внимание, что актерский состав действительно работает. - person Jon Skeet; 31.01.2018
comment
@JonSkeet Я пробовал что-то подобное раньше, и когда я развернул код, сборка не удалась, и до сих пор я не понимаю, почему, вот мой код: MyNullableEnum = product.type.HasValue ? (MyNullableEnum)product.type : null. Спасибо друг! - person Roxy'Pro; 19.02.2021
comment
@Roxy'Pro: Пожалуйста, внимательно сравните свой код с кодом в моем ответе. - person Jon Skeet; 19.02.2021
comment
@JonSkeet Я знаю, что ваш код работает, и когда я отредактировал свой код, чтобы он был похож на ваш, все работает, и я пытаюсь понять, почему мой код не работает. Я просто сказал, что «иначе» будет null : null , и в этом была проблема. Но я не уверен, почему, поскольку мое перечисление допускает значение null, оно должно принимать значение null в качестве значения? Спасибо Джон - person Roxy'Pro; 19.02.2021
comment
@ Roxy'Pro: тип перечисления с нулевым значением допускает нулевое значение ... но выражение product.type.HasValue ? (MyNullableEnum)product.type : null недопустимо по языковым правилам C #. Переменная или свойство, которым вы пытаетесь присвоить результат, не участвуют в выводе типа условного выражения. Если вы хотите получить более подробную информацию, задайте новый вопрос - подробный ответ будет длинным и будет относиться к конкретным частям спецификации С#. - person Jon Skeet; 19.02.2021

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

Для получения дополнительной информации я рекомендую прочитать блог Эрика Липперта: Представление и личность.

person Reed Copsey    schedule 04.03.2011
comment
На самом деле, не совсем. См. мой ответ - вы можете распаковать из упакованного int в тип перечисления (с int в качестве базового типа) или из упакованного значения перечисления в его базовый тип. - person Jon Skeet; 05.03.2011
comment
@Jon: Верно, но это также несколько пограничный случай (работает только потому, что в этом конкретном случае перечисление на самом деле является int) - что происходит, когда OP передает 0.0 в метод? Или они пытаются использовать эту технику с перечислением, поддерживаемым чем-то другим, кроме Int32? Они все равно вызовут проблемы... - person Reed Copsey; 05.03.2011
comment
Тогда он сломается. Но ОП говорит: объект может быть enum, null или int. Другими словами, решение, которое я дал, работает для проблемы в том виде, в каком она представлена. Мы не знаем, какое поведение желательно в других ситуациях. - person Jon Skeet; 05.03.2011

Когда вы присваиваете значение типу, допускающему значение NULL, вы должны знать, что оно не совпадает с базовым типом (по крайней мере, в этом случае). Итак, чтобы выполнить приведение, вам нужно сначала распаковать:

void Put(object value)
{
    if (value != null)
    {
        System.Nullable<Myenum> val = (System.Nullable<MyEnum>)(MyEnum)value;
    }
}
person TheBoyan    schedule 04.03.2011
comment
Это тоже не сработает. В этом коде та же ошибка: распаковка и приведение в одной и той же операции. Put должен получить MyEnum? в качестве параметра. - person Ilya Kogan; 05.03.2011
comment
+1, потому что это действительно работает. Те, кто говорит, что это не так, должны попробовать :) - person Jon Skeet; 05.03.2011
comment
Я попробовал это, прежде чем я разместил это, хотя :) - person TheBoyan; 05.03.2011
comment
Может быть, @IlyaKogan имел в виду, что это не работает, потому что val не назначается в случае, если value равно null. - person nawfal; 18.12.2013

немного оффтоп

Для тех, кому нужно, чтобы результат был нулевым, когда значение не определено в перечислении;

Следует использовать либо:

typeof(MyEnum).IsEnumDefined(val)

or

Enum.IsDefined(typeof(MyEnum), val)

Вот пример использования:

enum MyEnum { one = 1, three = 3, four=4 }

static MyEnum? CastIntAsNullableEnum(int value) 
{
    if (!Enum.IsDefined(typeof(MyEnum), value)) return null;
    return (MyEnum?)value;            
}

static void CastIntAsNullableEnumTest()
{
    for(int i =0; i<=5; i++)
    {
        Console.WriteLine("converted {0} is {1}", i, CastIntAsNullableEnum(i));
    }                        
}

Спасибо Джону Тириету (johnthiriet.com) за решение

person Pasetchnik    schedule 18.03.2020