如何在 C# 中获取枚举索引值
Posted
技术标签:
【中文标题】如何在 C# 中获取枚举索引值【英文标题】:How to get the Enum Index value in C# 【发布时间】:2011-09-06 23:52:26 【问题描述】:在 C 中,enums
内部等同于整数。因此,我们也可以将enum
的数据类型视为整数。
如何用 C# 实现相同的功能?
【问题讨论】:
重复:***.com/questions/29482/cast-int-to-enum-in-c(啊,枚举到 int 只是其他回答的强制转换) @Dmitry: 看起来另一个帖子实际上是相反的:) 【参考方案1】:首先,您可能指的是两个值:
基础价值
如果您询问基础值,它可以是以下任何一种类型:byte、sbyte、short、ushort、int、uint、long 或 ulong
然后您可以简单地将其转换为它的基础类型。假设它是int
,您可以这样做:
int eValue = (int)enumValue;
然而,还要注意每个项目的默认值(第一个项目是 0,第二个是 1,依此类推)以及每个项目都可以被分配一个新值的事实,这可能不会必须以任何顺序特定顺序! (感谢@JohnStock 澄清)。
此示例为每个分配一个新值,并显示返回的值:
public enum MyEnum
MyValue1 = 34,
MyValue2 = 27
(int)MyEnum.MyValue2 == 27; // True
指数价值
以上通常是最常用的值,也是您的问题详细信息表明您需要的值,但是每个值也有一个索引值(您在标题中引用)。如果您需要,请参阅下面的其他答案以获取详细信息。
【讨论】:
int 值不一定是下面 user1027167 的答案中所示的索引。再想一想,我认为 OP 是否真的想要索引或 int 值并不清楚...... 这个答案是错误的,并且对您的枚举做出了巨大的假设以使其正常工作。 @JohnStock 抱歉,哪里出了问题?你能详细说明一下吗?请记住,它是在大约 10 年前写的,是为了回应一个看似想要一个简单问题的简单答案的人而写的,所以做出了肯定的假设,显然它可以像往常一样变得更复杂,但它似乎已经满足了他们的要求! OP 正在请求索引。您的答案假定枚举具有一组一致的连续递增值,例如 1、2、3、4、5,这当然对于枚举来说通常是不正确的。它可能是相反的顺序,不是连续的,看似随机的值,甚至根本不是数字。您应该删除您的答案,因为它仅适用于非常特定的用例,并且在其他情况下会导致错误。如果您阅读此页面上的其他回复,您的解决方案(和其他人)中的此错误已被多次指出。 10 年没有任何改变 @JohnStock 啊,我明白了!好吧,我明白你在说什么,但老实说,如果他问的是什么,这取决于你的解释。尽管他在标题中声明了“索引”(我承认我错过了),但他关于枚举等于整数的实际问题表明,我相信在大多数情况下,指的是枚举的潜在价值,而不是特别是索引值本身。我想不出我自己曾经需要索引值的情况! (有吗??)所以是的,我在那里做了一个假设,并且仍然相信这是正确的决定,因为他接受了它。【参考方案2】:使用演员表:
public enum MyEnum : int
A = 0,
B = 1,
AB = 2,
int val = (int)MyEnum.A;
【讨论】:
【参考方案3】:使用简单的转换:
int value = (int) enum.item;
参考enum (C# Reference)
【讨论】:
【参考方案4】:using System;
public class EnumTest
enum Days Sat=1, Sun, Mon, Tue, Wed, Thu, Fri;
static void Main()
int x = (int)Days.Sun;
int y = (int)Days.Fri;
Console.WriteLine("Sun = 0", x);
Console.WriteLine("Fri = 0", y);
【讨论】:
【参考方案5】:默认情况下,枚举中每个元素的基础类型是整数。
enum Values
A,
B,
C
您还可以为每个项目指定自定义值:
enum Values
A = 10,
B = 11,
C = 12
int x = (int)Values.A; // x will be 10;
注意:默认情况下,第一个枚举数的值为 0。
【讨论】:
第二个枚举值呢?是 1 吗?【参考方案6】:另一种将 Enum-Type 转换为 int 的方法:
enum E
A = 1, /* index 0 */
B = 2, /* index 1 */
C = 4, /* index 2 */
D = 4 /* index 3, duplicate use of 4 */
void Main()
E e = E.C;
int index = Array.IndexOf(Enum.GetValues(e.GetType()), e);
// index is 2
E f = (E)(Enum.GetValues(e.GetType())).GetValue(index);
// f is E.C
更复杂但独立于分配给枚举值的 INT 值。
【讨论】:
这是一个比已接受的答案(或许多其他类似答案)更好的答案,因为它们似乎都假设您的枚举值是用连续的数值分配的,但通常情况并非如此。 怪物!!!!不错的答案。在枚举类型泛化的方法中完美工作!谢谢 使用标志时要小心,索引是按标志的数字排序值计算的,而不是它们定义的顺序。在上面的例子中,如果你定义 A=1,C=4,B=2 那么 B 的索引仍然是 1,即使它是在 C 之后定义的。这可能会在使用复合标志时导致意外结果。同样在上面的例子中,如果我们添加一个新标志“AB = A | B',那么它的值将是 3,并且 C 的索引将从上面例子中的 2 变为 3,因为“AB' 位于 B 和 C 之间按索引顺序。【参考方案7】:你可以直接施法:
enum MyMonthEnum January = 1, February, March, April, May, June, July, August, September, October, November, December ;
public static string GetMyMonthName(int MonthIndex)
MyMonthEnum MonthName = (MyMonthEnum)MonthIndex;
return MonthName.ToString();
例如:
string MySelectedMonthName=GetMyMonthName(8);
//then MySelectedMonthName value will be August.
【讨论】:
【参考方案8】:设计者 c# 可能选择不使用枚举自动转换的一个原因是为了防止意外混合不同的枚举类型......
e.g. this is bad code followed by a good version
enum ParkingLevel GroundLevel, FirstFloor;
enum ParkingFacing North, East, South, West
void Test()
var parking = ParkingFacing.North; // NOT A LEVEL
// WHOOPS at least warning in editor/compile on calls
WhichLevel(parking);
// BAD wrong type of index, no warning
var info = ParkinglevelArray[ (int)parking ];
// however you can write this, looks complicated
// but avoids using casts every time AND stops miss-use
void Test()
ParkingLevelManager levels = new ParkingLevelManager();
// assign info to each level
var parking = ParkingFacing.North;
// Next line wrong mixing type
// but great you get warning in editor or at compile time
var info=levels[parking];
// and.... no cast needed for correct use
var pl = ParkingLevel.GroundLevel;
var infoCorrect=levels[pl];
class ParkingLevelInfo /*...*/
class ParkingLevelManager
List<ParkingLevelInfo> m_list;
public ParkingLevelInfo this[ParkingLevel x]
get return m_list[(int)x];
【讨论】:
【参考方案9】:在回答这个问题时,我将“值”定义为枚举项的值,并将索引定义为枚举定义中的位置(按值排序)。 OP的问题要求“索引”,各种答案将其解释为“索引”或“值”(根据我的定义)。有时索引等于数值。
没有答案专门解决了查找 Enum 是 Enum 标志的索引(不是值)的情况。
Enum Flag
none = 0 // not a flag, thus index =-1
A = 1 << 0, // index should be 0
B = 1 << 1, // index should be 1
C = 1 << 2, // index should be 2
D = 1 << 3, // index should be 3,
AandB = A | B // index is composite, thus index = -1 indicating undefined
All = -1 //index is composite, thus index = -1 indicating undefined
在 Flag Enums 的情况下,索引简单地由下式给出
var index = (int)(Math.Log2((int)flag)); //Shows the maths, but is inefficient
但是,上面的解决方案是 (a) 正如@phuclv 所指出的那样效率低下(Math.Log2() 是浮点且成本高昂)和 (b) 没有解决 Flag.none 的情况,也没有解决任何复合标志 - 由其他标志组成的标志(例如我的示例中的 'AandB' 标志)。
DotNetCore 如果使用 dot net core,我们可以同时解决上面的 a) 和 b),如下所示:
int setbits = BitOperations.PopCount((uint)flag); //get number of set bits
if (setbits != 1) //Finds ECalFlags.none, and all composite flags
return -1; //undefined index
int index = BitOperations.TrailingZeroCount((uint)flag); //Efficient bit operation
不是 DotNetCore BitOperations 仅适用于点网核心。请参阅此处的@phuclv 答案以获取一些有效的建议https://***.com/a/63582586/6630192
@user1027167 根据我对他的回答的评论,如果使用复合标志,则答案将不起作用 感谢@phuclv 提供有关提高效率的建议【讨论】:
Math.Log2
很慢,BitOperations.TrailingZeroCount
会快很多。而且你不需要Convert.ToInt32
来获得一个int,一个简单的演员就足够了How to get numeric position of an enum in its definition list?
这假定了“索引”的特定定义(尽管请注意,在实际问题中,当 OP 说“索引”时,它们实际上是指“值”);可以提出一个有效的论点,即“索引”应该引用枚举值已定义,因此由于None=0
首先是定义,它的索引为0 - 但是然后会遇到进一步的复杂情况,因为反射 API 的顺序本身并没有定义!我的观点:这个答案中有很多定义性的东西被隐含地假定为公理,但比这更微妙
@Marc Gravell 同意“索引”和“价值”之间存在歧义。因此,我们将 'value' 定义为枚举项的值,并将 index 定义为枚举定义中的位置(按值排序)。还有许多其他问题与值有关,但我来这里是专门寻找索引的位置。许多其他答案也隐含地定义了索引,并且与值分开(请参阅@user1027167)。关于 None=0,在 Flags Enum 中它不能被视为索引,因为它不能用作 Flag..不过,这是一个很好的观点。
“和索引作为枚举定义中的位置位置(按值排序)” - 这些是相互矛盾的陈述;枚举定义不必按值排序(并且值不必是不同的),并且在运行时推断定义顺序也不可能,因为反射 API 明确不定义/保证订单
@MarcGravell。嗨,Marc,只关注枚举标志,虽然值可能不需要不同,但我们总是将它们定义为不同的,因为这是标志不同所必需的。鉴于此,标志的索引或不同标志按标志的数值排序。例如,让标志为 A=1
以上是关于如何在 C# 中获取枚举索引值的主要内容,如果未能解决你的问题,请参考以下文章