如何获得枚举在其定义列表中的数值位置

本文关键字:位置 列表 定义 何获得 枚举 | 更新日期: 2023-09-27 17:50:49

我需要得到枚举定义中的数字位置。考虑下面的enum -它用于位字段,但用于状态名如果它们的右边有我注释过的值,

[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 Array.IndexOf(Enum.GetValues(typeof(StatusFlags)), flag);
}

,只是遗漏了语法要点,即IndexOf是Array类中的静态函数,而不是扩展方法。我喜欢它,因为它简洁。

你可以这样做:

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();
}

直接用数学怎么样?他说旗子以2的幂上升

int GetStatusID(this StatusFlags flag)
{
    if (((int)flag) == 0) return 0;
    return (Math.Log((double)flag) / Math.Log(2D)) + 1;
}

如果每个标志只设置了1位,那么索引就是Math.Log2((int)flag) + 1。但是Math.Log2是一个浮点运算,非常慢所以不要使用它

如果你使用。net Core,那么有BitOperations.Log2BitOperations.TrailingZeroCount直接映射到硬件指令,如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框架,那么计算看看在这些问题中快速计算整数log2的方法

    在c#中计算整数log2的最快方法是什么?
  • log2(int)和log2(float)的最快实现
  • 在64位整数
  • 中查找最高和最低有效位集的快速方法