怎么可以 int
被投到一个 enum
在C#?
怎么可以 int
被投到一个 enum
在C#?
从字符串:
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);
// the foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")
来自int:
YourEnum foo = (YourEnum)yourInt;
更新:
从数字你也可以
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
只是施展它:
MyEnum e = (MyEnum)3;
你可以检查它是否在范围内使用 Enum.IsDefined:
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
或者,使用扩展方法而不是单行:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
用法:
Color colorEnum = "Red".ToEnum<Color>();
要么
string color = "Red";
var colorEnum = color.ToEnum<Color>();
我想要得到一个完整的答案,人们必须知道enums如何在.NET内部工作。
事情怎么样
.NET中的枚举是一组将一组值(字段)映射到基本类型的结构(默认为 int
)。但是,您实际上可以选择枚举映射到的整数类型:
public enum Foo : short
在这种情况下,枚举被映射到 short
数据类型,这意味着它将作为简短存储在内存中,并在您投射和使用它时表现为短。
如果从IL的角度来看它,(normal,int)枚举如下所示:
.class public auto ansi serializable sealed BarFlag extends System.Enum
{
.custom instance void System.FlagsAttribute::.ctor()
.custom instance void ComVisibleAttribute::.ctor(bool) = { bool(true) }
.field public static literal valuetype BarFlag AllFlags = int32(0x3fff)
.field public static literal valuetype BarFlag Foo1 = int32(1)
.field public static literal valuetype BarFlag Foo2 = int32(0x2000)
// and so on for all flags or enum values
.field public specialname rtspecialname int32 value__
}
这里应该引起你注意的是 value__
与枚举值分开存储。在枚举的情况下 Foo
以上,类型 value__
是int16。这基本上意味着你可以在枚举中存储你想要的任何东西, 只要类型匹配。
在这一点上,我想指出这一点 System.Enum
是一种值类型,基本上就是这个意思 BarFlag
将占用内存中的4个字节 Foo
将占用2 - 例如基础类型的大小(实际上比这更复杂,但是嘿......)。
答案
因此,如果你有一个想要映射到枚举的整数,那么运行时只需做两件事:复制4个字节并将其命名为其他东西(枚举的名称)。复制是隐式的,因为数据存储为值类型 - 这基本上意味着如果使用非托管代码,则可以简单地交换枚举和整数而无需复制数据。
为了安全起见,我认为这是最好的做法 知道底层类型是相同的或隐式可转换的 并确保存在枚举值(默认情况下不会检查它们!)。
要查看其工作原理,请尝试以下代码:
public enum MyEnum : int
{
Foo = 1,
Bar = 2,
Mek = 5
}
static void Main(string[] args)
{
var e1 = (MyEnum)5;
var e2 = (MyEnum)6;
Console.WriteLine("{0} {1}", e1, e2);
Console.ReadLine();
}
请注意,转换为 e2
也有效!从上面的编译器角度来看,这是有道理的: value__
字段只是填充5或6和何时 Console.WriteLine
电话 ToString()
,的名字 e1
是在解决的同时解决了 e2
不是。
如果这不是您的意图,请使用 Enum.IsDefined(typeof(MyEnum), 6)
检查您要投射的值是否映射到定义的枚举。
另请注意,即使编译器实际检查了这一点,我也明确了枚举的基础类型。我这样做是为了确保我不会遇到任何意外。要查看这些惊喜,您可以使用以下代码(实际上我已经看到这在数据库代码中发生了很多):
public enum MyEnum : short
{
Mek = 5
}
static void Main(string[] args)
{
var e1 = (MyEnum)32769; // will not compile, out of bounds for a short
object o = 5;
var e2 = (MyEnum)o; // will throw at runtime, because o is of type int
Console.WriteLine("{0} {1}", e1, e2);
Console.ReadLine();
}
采用以下示例:
int one = 1;
MyEnum e = (MyEnum)one;
我正在使用这段代码将int转换为我的枚举:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
我觉得这是最好的解决方案。
以下是Enums的一个很好的实用程序类
public static class EnumHelper
{
public static int[] ToIntArray<T>(T[] value)
{
int[] result = new int[value.Length];
for (int i = 0; i < value.Length; i++)
result[i] = Convert.ToInt32(value[i]);
return result;
}
public static T[] FromIntArray<T>(int[] value)
{
T[] result = new T[value.Length];
for (int i = 0; i < value.Length; i++)
result[i] = (T)Enum.ToObject(typeof(T),value[i]);
return result;
}
internal static T Parse<T>(string value, T defaultValue)
{
if (Enum.IsDefined(typeof(T), value))
return (T) Enum.Parse(typeof (T), value);
int num;
if(int.TryParse(value,out num))
{
if (Enum.IsDefined(typeof(T), num))
return (T)Enum.ToObject(typeof(T), num);
}
return defaultValue;
}
}
如果你准备好了4.0 。净 框架,有一个新的 Enum.TryParse() 功能非常有用并且与[Flags]属性配合得很好。看到 Enum.TryParse方法(String,TEnum%)