C# 如何获取枚举在其定义列表中的数字位置?
我需要获取枚举在其定义中的数字位置。 考虑下面的枚举-它用于位字段,但用于状态名 如果他们的右边有我评论过的值,这将非常有用C# 如何获取枚举在其定义列表中的数字位置?,c#,enums,C#,Enums,我需要获取枚举在其定义中的数字位置。 考虑下面的枚举-它用于位字段,但用于状态名 如果他们的右边有我评论过的值,这将非常有用 [Flags] public enum StatusFlags { None = 0, // 0 -- these commented indexes are the numbers I also would like Untested = 1, // 1 to associate with
[Flags]
public enum StatusFlags
{
None = 0, // 0 -- these commented indexes are the numbers I also would like
Untested = 1, // 1 to associate with the enum names.
Passed_Programming = 2, // 2
Failed_Programming = 4, // 3
// ... many more
}
我创建了一个静态方法,如下所示,它可以满足我的需要
public static int GetStatusID(this StatusFlags flag)
{
int i = 0;
foreach (StatusFlags val in Enum.GetValues(typeof(StatusFlags)))
{
if (flag == val) break;
i++;
}
return i;
}
它是这样使用的:
StatusFlags f = StatusFlags.Failed_Programming;
// I want the position i.e value of 3 not the value the enum is associated with i.e 4
int Index = f.GetStatusID();
[Flags]
public enum StatusFlags
{
[Index=0]
None = 0,
[Index=1]
Untested = 1,
[Index=2]
Passed_Programming = 2,
[Index=3]
Failed_Programming = 4,
// ... many more
}
var type = typeof(StatusFlags);
var statusFlag = type.GetMember(StatusFlags.Untested.ToString());
var attributes = statusFlag [0].GetCustomAttributes(typeof(IndexAttribute),false);
var index = int.Parse(((IndexAttribute)attributes[0]).Index); //if you need an int value
有更好的方法吗?您可以这样做:
public static int GetStatusID(this StatusFlags flag)
{
return
Enum
.GetValues(typeof(StatusFlags))
.Cast<StatusFlags>()
.Select((f, n) => new { f, n })
.Where(fn => fn.f == flag)
.Select(fn => fn.n)
.DefaultIfEmpty(0)
.First();
}
public static int GetStatusID(此StatusFlags标志)
{
返回
枚举
.GetValues(类型(状态标志))
.Cast()
.选择((f,n)=>new{f,n})
.其中(fn=>fn.f==标志)
.选择(fn=>fn.n)
.DefaultIfEmpty(0)
.First();
}
此处删除的答案表明类似于
public static int GetStatusID(this StatusFlags flag)
{
return Array.IndexOf(Enum.GetValues(typeof(StatusFlags)), flag);
}
只是缺少了一个语法点,IndexOf是Array类中的一个静态函数,而不是一个扩展方法。不过为了简洁,我喜欢它。用数学怎么样?他说国旗以2的幂升
int GetStatusID(this StatusFlags flag)
{
if (((int)flag) == 0) return 0;
return (Math.Log((double)flag) / Math.Log(2D)) + 1;
}
在枚举上使用属性如何?大概是这样的:
StatusFlags f = StatusFlags.Failed_Programming;
// I want the position i.e value of 3 not the value the enum is associated with i.e 4
int Index = f.GetStatusID();
[Flags]
public enum StatusFlags
{
[Index=0]
None = 0,
[Index=1]
Untested = 1,
[Index=2]
Passed_Programming = 2,
[Index=3]
Failed_Programming = 4,
// ... many more
}
var type = typeof(StatusFlags);
var statusFlag = type.GetMember(StatusFlags.Untested.ToString());
var attributes = statusFlag [0].GetCustomAttributes(typeof(IndexAttribute),false);
var index = int.Parse(((IndexAttribute)attributes[0]).Index); //if you need an int value
然后,您可以按如下方式设置枚举的索引值:
StatusFlags f = StatusFlags.Failed_Programming;
// I want the position i.e value of 3 not the value the enum is associated with i.e 4
int Index = f.GetStatusID();
[Flags]
public enum StatusFlags
{
[Index=0]
None = 0,
[Index=1]
Untested = 1,
[Index=2]
Passed_Programming = 2,
[Index=3]
Failed_Programming = 4,
// ... many more
}
var type = typeof(StatusFlags);
var statusFlag = type.GetMember(StatusFlags.Untested.ToString());
var attributes = statusFlag [0].GetCustomAttributes(typeof(IndexAttribute),false);
var index = int.Parse(((IndexAttribute)attributes[0]).Index); //if you need an int value
如果每个标志只有1个这样的位,那么索引就是
Math.Log2((int)标志)+1
。但是,这是一个浮点运算,速度非常慢,所以不要使用它
如果您使用的是.NET内核,那么就有和直接映射到硬件指令,如x86中的TZCNT/BSF或ARM中的CLZ,因此效率更高,结果如下
public static int GetStatusID(this StatusFlags flag)
{
if ((int)flag == 0)
return 0;
return BitOperations.Log2((int)flag);
// or return BitOperations.TrailingZeroCount((int)flag) + 1;
}
如果您使用的是较旧的.NET framework,请参见以下问题中快速计算整数log2的方法
Foo.X==Foo.Y
。还要注意,Enum.GetValues()
不会按声明顺序返回值,而是按基础值的大小顺序返回值。请参阅枚举值是否为2的幂?此外,返回0是不明确的(未找到/首先)。这些值是2的幂,因为枚举的主要目的是用于位字段。不会有重复的值。这些值是按数量级递增的顺序声明的,因此GetStatusID()应该可以工作。将编辑函数以删除不明确的返回值。如果值是唯一的,则可以使用以2为底的对数来获得每个值的2的幂。如果且仅当值是唯一的,则这些值将与基于1的值相同index@ReeCube-它不需要状态,是一个纯函数。可能较慢的想法我认为在这种情况下,使用LINQ只会模糊代码的含义。一个简单的环在眼睛上更容易…@JoãoAngelo-它在旁观者的眼睛里。我更喜欢这类东西,因为我可以自上而下地阅读代码,而不需要了解任何代码控制流。@PeterSchneider-它真的很简单-。选择(f,n)=>
重载使用值f
的当前索引填充n
。它只是一个带有值和索引的select,而不是像普通select扩展那样的值。请注意,当标志不存在时,IndexOf返回-1,这将OP的默认值0更改为更合理的值。MSDN文档在这里。为了简洁起见,像这样。同样像LINQ一样,这可能会很有用。你忘记了在返回中从double转换为int。这是我不知道的:)使用Math.Log(2D)作为常量也会更好。这也很好。这几乎就像在一个枚举中有n个枚举(因为可以有更多属性)。它不能保证连续的或唯一的索引可能是一个优点或缺点,这取决于用例。