如何将泛型枚举转换为int?

时间:2013-06-06 11:07:32

标签: c# enums

我有一个小方法,如下所示:

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。有没有办法做到这一点?

13 个答案:

答案 0 :(得分:36)

试试这个,

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
                        ..........
                        ..........
        }
    }
}

答案 1 :(得分:13)

您还可以先将值转换为object,然后再转换为int

C#7.3及更高版本

具有Enum通用约束。

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

低于C#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继承,则强制转换为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,它将使用int32的IConvertible接口转换不兼容的类型。

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

请注意,将uint转换为int和有符号/无符号对可能会导致意外行为。 (装箱到IConvertible,转换的效果不如装箱。)


我建议为每种枚举基类型创建一个方法,以确保返回正确的结果。

答案 2 :(得分:5)

这个正在使用任何基础类型

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())));
}

这为我们做了一切。

答案 3 :(得分:3)

如果目标是.NET Core,则可以使用Unsafe.As<TFrom, TTo>名称空间中的System.Runtime.CompilerServices,如MSDN所述。这样做的好处是不需要装箱,这是这里其他答案中唯一的实际性能成本。

private static int EnumToInt<TEnum>(TEnum enumValue) where TEnum : Enum
{
    return Unsafe.As<TEnum, int>(enumValue);
}

请注意,此方法与其他现有答案一样也存在安全问题:不能保证给定的枚举是兼容的int类型,这很可能是未烘焙此功能的相同原因。如果在内部使用此方法,可以确保传递给它的任何枚举是兼容类型,那么这可能是最有效的方法。

Here是指向dotnet GitHub页面上某个问题的链接,该问题在此处提出,如果您想了解更多,一些开发人员就此方法进行了详细说明。

答案 4 :(得分:3)

这是我的C#7.3及更高版本的解决方案。与OP的问题不完全匹配,但对于从Google找到这个问题的人来说可能很有用。相对于其他答案的主要优势是它返回了ulong,这意味着任何允许的枚举类型都将适合其中。为此,我还制作了comparison的机器代码和其他一些答案。是的,我很无聊,并且想过早进行优化。

private static unsafe ulong EnumAsUInt64<T>(T item) where T : unmanaged, Enum
{
    ulong x;
    if (sizeof(T) == 1)
        x = *(byte*)(&item);
    else if (sizeof(T) == 2)
        x = *(ushort*)(&item);
    else if (sizeof(T) == 4)
        x = *(uint*)(&item);
    else if (sizeof(T) == 8)
        x = *(ulong*)(&item);
    else
        throw new ArgumentException("Argument is not a usual enum type; it is not 1, 2, 4, or 8 bytes in length.");
    return x;
}

答案 5 :(得分:2)

我很惊讶你的代码可以运行。 Enum.GetValues返回一个整数数组 - 这是您要查找的值。而且,正如其他人所提到的,you can't constrain your generics to an enum

相反,您应该将Description方法称为常规静态方法,而不是扩展方法。

答案 6 :(得分:2)

你可以滥用 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

答案 7 :(得分:1)

派对有点晚了,但是使用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());
}

答案 8 :(得分:1)

这是一种更简单的方法。

由于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);

}

答案 9 :(得分:1)

只需将通用T强制转换为对象

T value;
int int_value = (int)(object)value;

就是这样。

答案 10 :(得分:0)

尝试以下操作:(假设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()));
    }
}

答案 11 :(得分:0)

如果使用限制通用T为枚举

where T: Enum

然后您可以使用下面的单层纸

public static int GetIndexFromEnum<T>(T enumValue) where T : Enum {
    int index = Convert.ToInt32(enumValue);
    return index;
}

这似乎是最简单的解决方案,只要您可以确保T将成为枚举即可。

答案 12 :(得分:-3)

扩展Jan关于泛型和枚举值的答案:

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