Как конфертировать из System.Enum в базовое целое число? - PullRequest
88 голосов
/ 26 мая 2009

Я хотел бы создать универсальный метод для преобразования любого производного типа 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"));
    }
}

Есть предложения?

Ответы [ 8 ]

129 голосов
/ 26 мая 2009

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

Convert.ToInt32()

мог бы добиться цели.

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

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

37 голосов
/ 26 мая 2009

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

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

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

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

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));
    }
12 голосов
/ 09 ноября 2015

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

return System.Convert.ChangeType(
    enumValue,
    Enum.GetUnderlyingType(enumValue.GetType()));
11 голосов
/ 26 мая 2009

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

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

int x = (int)DayOfWeek.Tuesday;

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

int y = Converter.ToInteger(DayOfWeek.Tuesday);
// or
int z = DayOfWeek.Tuesday.ToInteger();
4 голосов
/ 01 декабря 2013

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

Дано 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();
1 голос
/ 26 мая 2009

Приведение с System.Enum к int отлично работает для меня (это также на MSDN ). Возможно, это ошибка Решарпера.

0 голосов
/ 12 марта 2018

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

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

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

  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);
  }
}
0 голосов
/ 26 мая 2009

Не забывайте, что сам тип 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);
...