C#:将int强制转换为枚举enum

您所在的位置:网站首页 vb强制转换为integer C#:将int强制转换为枚举enum

C#:将int强制转换为枚举enum

#C#:将int强制转换为枚举enum | 来源: 网络整理| 查看: 265

如何在一个int加压铸造enum#在C?

相关讨论 for the other方式:int get -圆-从-枚举值

从字符串:

1234YourEnum 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:

1YourEnum foo = (YourEnum)yourInt;

更新:

从数字上你也可以

1YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt); 相关讨论 正确的答案应该是:yourenum foo=(yourenum)enum.parse(typeof(yourenum),yourstring)或yourenum foo=(yourenum)enum.parse(typeof(yourenum),yourint)——如适用。 @flyswat,如果YourEnum是动态的,只在运行时知道,我想转换成Enum呢? "摆摆。如果枚举仅在运行时已知,请保持动态。类型安全性(强类型)只能由编译器来保证。不能在运行时强类型对象。最接近它的方法是使用泛型,但是必须在编译时知道泛型类型。T ToEnum(int x) { return (T)x; }但是没有直接铸造的真正优势。 快问,如果你从YourEnum foo回到int anInt型:anInt = (int)foo;行吗? @洛根当然,它能用。(如果枚举的基础整数类型不是int,则转换为基础整数类型。但是,底层类型应该是除int之外的其他类型是非常罕见的。) 请注意,如果代码被模糊化,那么enum.parse将不起作用。在模糊处理之后的运行时,将字符串与枚举名称进行比较,此时,枚举的名称并不是您期望的那样。您的分析将在以前成功的地方失败。 如果使用上面的"From a String"语法并传入一个无效的数字字符串(例如"2342342"--假设它不是枚举的值),那么它实际上允许这样做而不会引发错误!您的枚举将具有该值(2342342),即使它在枚举本身中不是有效的选择。 我想这个答案现在有点过时了。对于字符串,现在应该使用var result = Enum.TryParse(yourString, out yourEnum)(并检查结果以确定转换是否失败)。 @康罗伊法官,我不知道我是否同意。在我的程序中,如果转换失败,通常是一个不可恢复的错误,所以我希望抛出异常。 parse函数给出了一个令人烦恼的异常的经典例子。也就是说,在完全非异常情况下抛出的异常,通常是由于不幸的设计决策。C的开发人员认识到了这个不幸的设计,后来又添加了台盼来处理这个问题。Tryparse返回一个布尔值,该值指示分析是否成功或失败,因此应该使用该布尔值而不是异常处理程序。有关更多信息,请参阅EricLippert的博客文章。 通过向调用中添加true参数值,也可以使Enum.Parse不区分大小写:YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);。 即使枚举中不存在int值,从int转换是否可能工作?我刚在.NET 3.5中尝试过,但它似乎起作用了,这让人很困惑。 enum.toobject是我要找的。这正是动态处理枚举时所需要的,并且您知道某个类型是枚举,但无法向编译器证明它,因为编译器不允许您从int值强制转换为任意类型。 @santhos是的,有Enum.IsDefined()来检查您要转换的值是否存在于枚举中。 好答案。只是让我想知道,为什么这种高级语言对前代语言中自然简单得多的东西要求如此之高。在VisualBasic6中,可以超过int值或枚举。与其他现代语言相比,即使是PHP也允许直接传递int。 @康罗伊法官,但事实并非如此。当您调用Parse时,您相信输入值是正确的,如果不正确,则是代码中的一个错误(应该有一个例外)。如果要处理用户输入,则应始终调用TryParse,因为无效输入并不例外。你链接的文章在"99%的用户案例中提到这个方法是转换用户输入的字符串",这就是bug,这个方法不是为处理用户输入而设计的,TryParse是。 @Aidiakapi您有多少次尝试将字符串解析为整数,在这些整数中,您可以完全控制永远传递的值?;-) @Justintconroy,只要你相信你的意见。一个例子可以是序列化或保存文件。您可以相信文件的格式是正确的,如果不正确,只需抛出一个异常,因为您无论如何都要处理损坏的输入。大多数情况都与互操作性或兼容性有关。任何时候,当您在使用以字符串形式存储的ints的程序之间进行通信时,都会发生通信错误,并指示代码中存在错误。 这里有一个小提琴或repl来处理这个示例repl.it/ejcv/1。

只是投下:

1MyEnum e = (MyEnum)3;

您可以使用Enum.IsDefined检查它是否在范围内:

1if (Enum.IsDefined(typeof(MyEnum), 3)) { ... } 相关讨论 注意,如果使用flags属性并且该值是标志的组合,则不能使用enum.isDefined,例如:keys.l keys.control 关于Enum.IsDefined,请注意它可能很危险:msdn.microsoft.com/en-us/library/ms229025(vs.90).aspx 另一方面,如果我根据库提供的枚举验证输入,在将其发送到库本身之前… 我更喜欢这个定义:"返回指定枚举中是否存在具有指定值的常量"来自msdn …因为你的定义可能误导,因为你说:"…检查它是否在范围内…",这意味着在一个有起始和结束限制的数字范围内… 请注意,枚举的值默认为int,但可以更改该值,这可能会造成强制转换的危险。查看@atlastes的答案。 如果在我强制转换枚举时该值不存在,会发生什么? @阿德里安,你能提供一个简单的危险场景的例子吗?在那个医生面前绕着我的头有困难。 @mac9416我试图在gist.github.com/alowdon/f7354cda97bac70b44e1c04bc0991bcc上给出一个简洁的例子-基本上,通过使用IsDefined检查输入值,您会让自己容易受到稍后添加新枚举值的人的攻击,这将通过IsDefined检查(因为新值存在于新代码中),但可能不适用于你写的原始代码。因此,显式地指定代码能够处理的枚举值更安全。

或者,使用扩展方法而不是一个衬板:

1234public static T ToEnum(this string enumString) {     return (T) Enum.Parse(typeof (T), enumString); }

用途:

1Color colorEnum ="Red".ToEnum();

12string color ="Red"; var colorEnum = color.ToEnum(); 相关讨论 对于处理用户输入,调用枚举的重载可能是一个好主意。parse也就是说,允许您指定不区分大小写的比较(即,用户键入"red"(小写)将在不进行此更改的情况下破坏上述代码)。 很酷,只是这不是问题。 很方便,但这个问题专门问关于ints的问题。 如果字符串是一个整数,例如"2",这也适用。 如果EnumString为空(昨天有类似问题),则会引发异常。考虑使用胰蛋白酶而不是解析。typarse还将检查t是否是枚举类型

我认为要得到一个完整的答案,人们必须知道Enums如何在.NET内部工作。

素材如何工作

.NET中的枚举是将一组值(字段)映射到基本类型(默认值为int)的结构。但是,实际上可以选择枚举映射到的整型:

1public enum Foo : short

在这种情况下,枚举被映射到short数据类型,这意味着它将作为short存储在内存中,并在您强制转换和使用它时表现为short。

如果从IL的角度来看,则(normal,int)枚举如下:

12345678910111213.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个字节,并将其命名为其他东西(枚举的名称)。复制是隐式的,因为数据存储为值类型——这基本上意味着如果使用非托管代码,则可以简单地交换枚举和整数而不复制数据。

为了安全起见,我认为最好的做法是知道基础类型是相同的或隐式可转换的,并确保枚举值存在(默认情况下不会检查它们!).

要了解这是如何工作的,请尝试以下代码:

123456789101112131415public 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)检查您要强制转换的值是否映射到定义的枚举。

另外请注意,我对枚举的基础类型很明确,即使编译器实际上检查了这一点。我这样做是为了确保我不会在路上遇到任何意外。要看到这些意外的行为,您可以使用以下代码(实际上,我在数据库代码中看到过很多这样的情况):

123456789101112131415public 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(); } 相关讨论 我知道这是一个古老的职位,但是你如何在C中获得这一级别的知识?这是通过阅读C规范得出的吗? @罗兰,我有时候希望更多的人会问这个问题。:-)老实说,我不太清楚,我试着理解事情是如何运作的,并在我能得到的地方获取信息。我确实读过C标准,但我也经常用Reflector(我甚至经常看x86汇编程序代码)对代码进行反编译,并做了大量的小实验。另外,了解其他语言在这种情况下也会有所帮助;我已经做了大约30年的CS,并且在某种程度上某些事情会变得"合乎逻辑"-f.ex。枚举应该是整型的,因为否则互操作将中断(或者您的性能将耗尽)。 我相信正确地进行软件工程的关键是知道东西是如何工作的。对我来说,这意味着如果你写了一段代码,你就知道它是如何粗略地翻译成F.Ex.处理器操作和内存提取/写入的。如果你问如何达到这个水平,我建议建立大量的小测试用例,让它们变得更难,每次都试着预测结果,然后测试它们(包括反编译等)。在弄清楚所有的细节和特性之后,你可以检查一下你是否在(枯燥的)标准中得到了正确的结果。至少,这是我的方法。 非常好的回答,谢谢!在上一个代码示例中,它在运行时抛出一个异常,因为O是一个对象。只要int变量在短范围内,就可以将其强制转换为short。 @万有引力谢谢。实际上,这是一个拆箱操作,因此它不会像您描述的那样进行任何隐式转换。如果你不知道细节的话,在C中的演员阵容有时会令人困惑…无论如何,因为int!=short,会抛出(拆箱失败)。如果您执行object o = (short)5;,它将工作,因为类型将匹配。它不是关于范围,而是关于类型。 @Atlaste,如果MyEnum衍生出(或是?)从int中,为什么没有显式转换就不能为MyEnum类型的变量分配int值?是否有可能在没有显式强制转换的情况下,以某种方式使分配工作正常进行? @Heyjude,这仅仅是因为C dev团队认为这是正确的语法。它基本上避免使用未定义的整数值使枚举活动(例如,否则可以将任何枚举设置为任何值)。在像C++这样的其他语言中,这是可能的。

例如:

12int one = 1; MyEnum e = (MyEnum)one;

我使用这段代码将int强制转换为枚举:

12if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast; else { //handle it here, if its not defined }

我觉得这是最好的解决办法。

相关讨论 不适用于标志枚举 这很好。我很惊讶在将无效值强制转换为int-backed枚举时没有异常。 这实际上与最高评价的答案没什么不同。该答案还讨论了在将字符串强制转换为枚举类型之后使用Enum.IsDefined。因此,即使字符串被无错误地强制转换,Enum.IsDefined仍将捕获它

下面是一个很好的枚举实用程序类

12345678910111213141516171819202122232425262728293031323334public static class EnumHelper {     public static int[] ToIntArray(T[] value)     {         int[] result = new int[value.Length];         for (int i = 0; i {                 if (i y);         var maxPossible = candidates.Sum();         if (             Enum.TryParse(val.ToString(), out TEnum asEnum)             && (val (int)Math.Pow(2, n))             .Where(n => n 0 && !candidates.Contains(n))             .Sum();         return Enum.TryParse((val - excess).ToString(), out asEnum) ? asEnum : default(TEnum);     }

只需使用显式转换cast int to enum或enum to int

123456789101112131415161718class Program     {         static void Main(string[] args)         {             Console.WriteLine((int)Number.three); //Output=3             Console.WriteLine((Number)3);// Outout three             Console.Read();         }         public enum Number         {             Zero = 0,             One = 1,             Two = 2,             three = 3                   }     }



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3