我修改了Thorarin在回答this问题时提供的扩展方法,以处理int而不是字符串:
public static TEnum ToEnum<TEnum>(this int intEnumValue, TEnum defaultValue)
{
if (!Enum.IsDefined(typeof(TEnum), intEnumValue))
return defaultValue;
return (TEnum)intEnumValue;
}
编译器给出错误“无法将类型'int'转换为'TEnum'。”在最后一行。
如果该行更改为:
return (TEnum)(object)intEnumValue;
它编译并运作。
为什么首先需要将int转换为对象?
答案 0 :(得分:5)
将int
直接转换为未知类型是不可能的,因此编译器不允许(TEnum)intEnumValue
。您现在正在进行的两个演员实际上略有不同:(object)
框int
,而(TEnum)
将框int
投放到TEnum
,这是静态的允许,因为静态类型object
的表达式实际上可能是运行时类型TEnum
。
可能还会有一些细微之处:通常情况下,装箱int
can only be unboxed to int
。我想我已经解释了为什么编译器允许转换,但不解释为什么运行时也允许转换。也许仅在运行时允许转换为TEnum
,因为TEnum
恰好是以int
为基本类型的枚举?我想我记得读过CLR中的枚举实际上只是它们基类型的实例。
编辑:我确认了我的怀疑:
public static void Main()
{
int value = 1;
IntEnum i = ToEnum<IntEnum>(value); // Valid cast, runs fine.
ByteEnum b = ToEnum<ByteEnum>(value); // Invalid cast exception!
}
public enum ByteEnum : byte { }
public enum IntEnum : int { }
public static TEnum ToEnum<TEnum>(int value)
{
return (TEnum)(object)value;
}
因此,我们可以有把握地说,(TEnum)
盒装int
仅在TEnum
实际上是int
的情况下才有效!
答案 1 :(得分:2)
Eric Lippert有一篇关于此类问题的博文here。基本上,有几种不同类型的'cast',从int到TEnum可能是其中之一。因此,唯一安全的方法是将int打包到一个对象,然后尝试在运行时将其转换为TEnum。你不能直接从int到TEnum,因为需要做的事情取决于TEnum是什么,而且只在运行时才知道。
答案 2 :(得分:0)
使用(TEnum)intEnumValue进行转换时,编译器不知道TEnum将成为何种类。由于int只能隐式转换为某些类,因此编译器会失败。可以接受转换为对象,然后TEnum是一个对象,因此也可以进行转换。
答案 3 :(得分:0)
TEnum是一种任意类型。你能把int转换为Rectangle吗?到DateTime?编译器不知道,不幸的是规范说你不能在它上面添加约束。