Подтвердить что ты не робот

Как я могу привести общий enum к int?

У меня есть небольшой метод, который выглядит так:

public void SetOptions<T>() where T : Enum
{
    int i = 0;
    foreach (T obj in Enum.GetValues(typeof(T)))
    {
        if (i == 0)
            DefaultOption = new ListItem(obj.Description(), obj.ToString());
        i++;
        DropDownList.Items.Add(new ListItem(obj.Description(), obj.ToString()));
    }
}

По сути, я заполняю выпадающий список из перечисления. Description() на самом деле является методом расширения для перечислений, поэтому T определенно является enum.

Тем не менее, я хочу привести obj же, как и любое другое перечисление к его индексу, как этот (int)obj, но я получаю сообщение о том, что не могу преобразовать T в int. Есть ли способ сделать это?

4b9b3361

Ответ 1

попробуйте это,

public void SetOptions<T>()
{
    Type genericType = typeof(T);
    if (genericType.IsEnum)
    {
        foreach (T obj in Enum.GetValues(genericType))
        {
            Enum test = Enum.Parse(typeof(T), obj.ToString()) as Enum;
            int x = Convert.ToInt32(test); // x is the integer value of enum
                        ..........
                        ..........
        }
    }
}

Ответ 2

Вы также можете перенести свое значение на object а затем на int.

С# 7.3 и выше

С общим ограничением Enum.

public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
    => (int)(object)value;

Ниже С# 7.3

Без общего ограничения Enum.

public static int EnumToInt<TValue>(this TValue value)  where TValue : struct, IConvertible
{
    if(!typeof(TValue).IsEnum)
    {
        throw new ArgumentException(nameof(value));
    }

    return (int)(object)value;
}

Если ваше перечисление наследуется от других типов, например, из byte метод cast to int будет InvalidCastException.

Вы можете проверить, является ли базовый тип перечисления целым числом.

public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
{
    if (!typeof(int).IsAssignableFrom(Enum.GetUnderlyingType(typeof(TValue))))
        throw new ArgumentException(nameof(TValue));

    return (int)(object)value;
}

Или, если вы используете Convert.ToInt32 он будет использовать IConvertible интерфейс int32 для преобразования несовместимых типов.

public static int EnumToInt<TValue>(this TValue value) where TValue : Enum
    => Convert.ToInt32(value);

Просто имейте в виду, что преобразование uint в int и подписанные/неподписанные пары могут вызвать непреднамеренное поведение. (Бокс для IConvertible и конвертация менее результативна, чем просто распаковка).


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

Ответ 3

Этот работает с любым базовым типом

Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType()))

Когда это применимо? Например, если вы хотите добавить значение в SqlCommand, которое преобразует перечисления в 0 и вы должны явно применить его к соответствующему типу. Но мы можем написать следующее расширение:

public static void AddEnum(this SqlParameterCollection parameters, string parameterName, Enum value)
{
    parameters.AddWithValue(parameterName, Convert.ChangeType(value, Enum.GetUnderlyingType(value.GetType())));
}

Что делает все для нас.

Ответ 4

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

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

Ответ 5

Можете ли вы злоупотреблять GetHashCode для этого?

public enum MyEnum
{
  Foo = 100,
  Bar = 200,
  Fizz = 0
}

static void Main(string[] args)
{
  var i1 = MyEnum.Foo.GetHashCode();  // i1 = 100
  var i2 = MyEnum.Bar.GetHashCode();  // i2 = 200
  var i3 = MyEnum.Fizz.GetHashCode(); // i3 = 0
}

Обратите внимание: "GetHashCode() по своей сути полезен только для одной вещи: помещение объекта в хэш-таблицу. Следовательно, это имя". - E. Lippert

Ответ 6

Используя LINQ, это можно сделать элегантно:

public static void SetOptions<T>(this DropDownList dropDownList)
{
    if (!typeof(T).IsEnum)
    {
        throw new ArgumentException("Type must be an enum type.");
    }

    dropDownList.Items.AddRange(Enum
        .GetValues(typeof(T))
        .Cast<Enum>()
        .Select(x => new ListItem(x.ToString(), Convert.ToInt32(x).ToString()))
        .ToArray());
}

Ответ 7

Здесь более простой способ.

Поскольку Enum реализует IConvertible, мы можем использовать ToInt32 (..).

int? value = (enumCandidate as IConvertible)?.ToInt32(CultureInfo.InvariantCulture.Numberformat);

Или если вы хотите использовать универсальный метод для общих перечислений:

public static int GetEnumValue<T>(T inputEnum) where T: struct, IConvertible
{
    Type t = typeof(T);
    if (!t.IsEnum)
    {
        throw new ArgumentException("Input type must be an enum.");
    }

    return inputEnum.ToInt32(CultureInfo.InvariantCulture.NumberFormat);

}

Или еще более общий:

public static int GetEnumValue(object enumInput)
{
    Type t = enumInput.GetType();
    if (!t.IsEnum)
    {
        throw new ArgumentException("Input type must be an enum.");
    }

    return ((IConvertible)inputEnum).ToInt32(CultureInfo.InvariantCulture.NumberFormat);

}

Ответ 8

Попробуйте это: (при условии, что TEnum имеет нумерацию от 0 до n)

public void SetOptions<TEnum>() where TEnum : Enum
{
    foreach (TEnum obj in Enum.GetValues(typeof(TEnum)))
    {
        var i = (int)(object)obj;
        if (i == 0) DefaultOption = new ListItem(obj.Description(), obj.ToString());
        DropDownList.Items.Add(new ListItem(obj.Description(), obj.ToString()));
    }
}

Ответ 9

Чтобы развернуть ответ Jan относительно дженериков и значений перечисления:

void MyFunc<T>(T value)
{
    Type t = typeof(T);
    if(t.IsEnum)
    {
        int valueAsInt = value.GetHashCode(); // returns the integer value
    }
}