可能出现Enum整型强制转换异常
本文关键字:转换 异常 整型 Enum | 更新日期: 2023-09-27 18:11:01
给定下面的代码,int
强制转换是否有可能抛出异常?
static void foo(Type typeEnum)
{
if (typeEnum.IsEnum)
{
foreach (var enumVal in Enum.GetValues(typeEnum))
{
var _val = (int)enumVal;
}
}
}
是,如果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));
然后,如果他们得到一个异常,它落在他们指定正确的大小类型…
枚举是一种奇怪的东西。它们可以继承long,但仍然是枚举。
我很确定这段理论代码会抛出一个强制类型转换异常,如果你接受一个这样做的enum
正如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页面有样例代码,几乎与我的样例代码所做的完全相同)。
Enum.GetValues
实际上返回的是该特定enum类型的数组。
没有提到的是,如果TEnum:int
或TEnum:uint
,特定的数组也可以转换为int[]
(无论签名如何,原语的CLR数组都是可转换的)。否则,为了安全起见,您可以始终使用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));
}
}
}
}