Enum Integer Cast异常可能吗?

时间:2011-10-11 15:24:54

标签: c# casting enums

鉴于下面的代码,int演员是否有可能抛出异常?

        static void foo(Type typeEnum)
        {
            if (typeEnum.IsEnum)
            {
                foreach (var enumVal in Enum.GetValues(typeEnum))
                {
                    var _val = (int)enumVal;                      
                }
            }
        }

4 个答案:

答案 0 :(得分:5)

是的,如果enum支持类型不是int,例如:

    public enum X : long
    {
        A,
        B,
        C
    }

这将抛出。这是因为enum值是object的框,并且您不能将'object'强制转换为'int',除非包含的值实际上是'int'。

您可以通过执行适用于Convert.ToInt32()或更小的所有支持类型的int来缓解此问题:

static void foo(Type typeEnum)
{
    if (typeEnum.IsEnum)
    {
        foreach (var enumVal in Enum.GetValues(typeEnum))
        {
            var _val = Convert.ToInt32(enumVal);                      
        }
    }
}

或者,如果您想假设int并且更安全,可以检查enum的基础类型:

if (Enum.GetUnderlyingType(typeEnum) != typeof(int))
{
    throw new ArgumentException("This method only accepts int enums.");
}

或者,您可以假设long如果已签名,则ulong如果未签名(您可以包含负enum值,但往往更少见):

static void foo(Type typeEnum)
{
    if (typeEnum.IsEnum)
    {
        foreach (var enumVal in Enum.GetValues(typeEnum))
        {
            var _val = Convert.ToInt64(enumVal);                      
        }
    }
}

这就是为什么做出一些假设并在通话中检查它们可能更安全。你打算取消装箱值的任何东西都有可能抛出或溢出。

您甚至可以通用并让用户传递他们想要的类型:

static IEnumerable<ToType> foo<ToType>(Type typeEnum)
{
    if (typeEnum.IsEnum)
    {
        foreach (var enumVal in Enum.GetValues(typeEnum))
        {
            yield return (ToType)Convert.ChangeType(enumVal, typeof(ToType));
        }
    }
}

所以你可以调用它:

IEnumerable<int> values foo<int>(typeof(YourEnum));

然后,如果他们得到一个例外,它就落在他们身上以指定正确的尺寸类型......

答案 1 :(得分:2)

Enums是奇怪的野兽。他们可能会继承很久而且仍然是枚举。

我很确定如果你采用这样做的枚举,这个理论代码会引发一个强制转换异常。

答案 2 :(得分:0)

正如James Michael Hare所提到的,枚举可以是long。但是,使用Convert.ToInt32不够好,因为您仍然可以获得溢出异常。想象一下,以下枚举的值大于甚至可以适合int:

public enum BigEnum : long
{
    BigValue = (long)int.MaxValue + 5
}

在这种情况下,无法将该值转换为int,因为它太大了。但是,您可以使用这样的逻辑,它不会抛出:

static void foo(Type typeEnum)
{
    var underlyingType = Enum.GetUnderlyingType(typeEnum);

    if (typeEnum.IsEnum)
    {
        foreach (var enumVal in Enum.GetValues(typeEnum))
        {
            var _val = Convert.ChangeType(enumVal, underlyingType);
        }
    }
}

它使用Enum.GetUnderlyingType方法确保对ChangeType的调用将使用正确的类型。 (事实上​​,GetUnderlyingType的MSDN页面的示例代码几乎完成了我的示例代码所做的事情。)

答案 3 :(得分:0)

Enum.GetValues实际上返回该特定枚举类型的数组。

未提及的是,如果int[]TEnum:int(基元的CLR数组无论签名是否可转换),特定数组也可转换为TEnum:uint 否则要防守你总是可以使用Convert.ChangeType(object,Type) api来保证安全。 因此,您可以将代码编写为:

    static void foo(Type typeEnum)
    {
        if (typeEnum.IsEnum)
        {
            var array = Enum.GetValues(typeEnum)
            int[] arrayAsInts = array as int[];
            if(arrayAsInts != null)
            { 
              foreach (var enumVal in arrayAsInts)
              {
                 var _val = enumVal;                      
              }
            }
            else
            {
              foreach (var enumVal in array)
              {
                 var _val = Convert.ChangeType(enumVal,typeof(int));                      
              }
            }
        }
    }