Как преобразовать System.Enum в базовое целое число?

StackOverflow https://stackoverflow.com/questions/908543

  •  05-09-2019
  •  | 
  •  

Вопрос

Я хотел бы создать универсальный метод для преобразования любого производного типа System.Enum в соответствующее целочисленное значение без приведения и, желательно, без анализа строки.

Например, я хочу что-то вроде этого:

// Trivial example, not actually what I'm doing.
class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        (int)anEnum;
    }
}

Но это, похоже, не работает.Resharper сообщает, что вы не можете привести выражение типа «System.Enum» к типу «int».

Теперь я придумал это решение, но я бы предпочел что-то более эффективное.

class Converter
{
    int ToInteger(System.Enum anEnum)
    {
        return int.Parse(anEnum.ToString("d"));
    }
}

Какие-либо предложения?

Это было полезно?

Решение

Если вы не хотите проводить кастинг,

Convert.ToInt32()

мог бы сделать свое дело.

Прямой состав (через (int)enumValue) это невозможно.Обратите внимание, что это также было бы «опасно», поскольку перечисление может иметь разные базовые типы (int, long, byte...).

Более формально: System.Enum не имеет прямых отношений наследования с Int32 (хотя оба ValueTypes), поэтому явное приведение не может быть правильным в рамках системы типов.

Другие советы

Я заставил его работать, приведя его к объекту, а затем к int:

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return (int)((object)enumValue);
    }
}

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

РЕДАКТИРОВАТЬ:Как раз собирался опубликовать, что Convert.ToInt32(enumValue) тоже работает, и заметил, что МартинСтеттнер опередил меня в этом.

public static class EnumExtensions
{
    public static int ToInt(this Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

Тест:

int x = DayOfWeek.Friday.ToInt();
Console.WriteLine(x); // results in 5 which is int value of Friday

РЕДАКТИРОВАТЬ 2:В комментариях кто-то сказал, что это работает только в C# 3.0.Я только что протестировал это в VS2005 вот так, и это сработало:

public static class Helpers
{
    public static int ToInt(Enum enumValue)
    {
        return Convert.ToInt32(enumValue);
    }
}

    static void Main(string[] args)
    {
        Console.WriteLine(Helpers.ToInt(DayOfWeek.Friday));
    }

Если вам нужно конвертировать любой enum к его базовому типу (не все перечисления поддерживаются int), то вы можете использовать:

return System.Convert.ChangeType(
    enumValue,
    Enum.GetUnderlyingType(enumValue.GetType()));

Зачем нужно изобретать велосипед с помощью вспомогательного метода?Совершенно законно разыгрывать enum значение к его базовому типу.

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

int x = (int)DayOfWeek.Tuesday;

...а не что-то вроде...

int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();

Из моего ответа здесь:

Данный e как в:

Enum e = Question.Role;

Тогда это работает:

int i = Convert.ToInt32(e);
int i = (int)(object)e;
int i = (int)Enum.Parse(e.GetType(), e.ToString());
int i = (int)Enum.ToObject(e.GetType(), e);

Последние два просто ужасны.Первый должен быть более читаемым, хотя второй намного быстрее.Или, может быть, метод расширения является лучшим, лучшим из обоих миров.

public static int GetIntValue(this Enum e)
{
    return e.GetValue<int>();
}

public static T GetValue<T>(this Enum e) where T : struct, IComparable, IFormattable, IConvertible, IComparable<T>, IEquatable<T>
{
    return (T)(object)e;
}

Теперь вы можете позвонить:

e.GetValue<int>(); //or
e.GetIntValue();

Кастинг из System.Enum для int у меня работает нормально (это также есть на MSDN).Возможно, это ошибка Resharper.

Поскольку Enums ограничены byte, sbyte, short, ushort, int, uint, long и ulong, мы можем сделать некоторые предположения.

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

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

  1. для перечислений, основанных на типе с пространством полей больше, чем int (long и ulong), возможно, некоторые перечисления будут иметь одно и то же значение.
  2. приведение числа большего, чем int.MaxValue, вызовет исключение, если вы находитесь в проверенном регионе.

Вот мое предложение: я оставлю читателю самому решать, где разместить эту функцию;в качестве помощника или расширения.

public int ToInt(Enum e)
{
  unchecked
  {
    if (e.GetTypeCode() == TypeCode.UInt64)
      return (int)Convert.ToUInt64(e);
    else
      return (int)Convert.ToInt64(e);
  }
}

Не забывайте, что сам тип Enum содержит множество статических вспомогательных функций.Если все, что вам нужно, — это преобразовать экземпляр перечисления в соответствующий ему целочисленный тип, то приведение типов, вероятно, является наиболее эффективным способом.

Я думаю, что ReSharper жалуется, потому что Enum не является перечислением какого-либо конкретного типа, а сами перечисления происходят от скалярного типа значения, а не от Enum.Если вам нужно универсальное адаптируемое приведение, я бы сказал, что это вам подойдет (обратите внимание, что сам тип перечисления также включен в общий:

public static EnumHelpers
{
    public static T Convert<T, E>(E enumValue)
    {
        return (T)enumValue;
    }
}

Затем это можно было бы использовать так:

public enum StopLight: int
{
    Red = 1,
    Yellow = 2,
    Green = 3
}

// ...

int myStoplightColor = EnumHelpers.Convert<int, StopLight>(StopLight.Red);

Я не могу сказать наверняка, но приведенный выше код может даже поддерживаться выводом типа C#, позволяя следующее:

int myStoplightColor = EnumHelpers.Convert<int>(StopLight.Red);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top