如何只从flags枚举值中获取第一个值,并按照添加的顺序获取它

时间:2013-11-28 13:34:53

标签: c#

我有以下代码:

[Flags()]
public enum Foo
{
    Unknown = 0x00,
    A = 0x01,
    B = 0x02,
    C = 0x04,
    D = 0x08,
}

public static class Extensions
{
    public static List<Foo> AsList(this Foo types)
    {
        List<Foo> list = new List<Foo>();
        foreach(Foo sT in Enum.GetValues(typeof(Foo)))
        {
            if ((sT & types) == sT) list.Add(sT);
        }
        return list;
    }

}

class Program
{
    static void Main(string[] args)
    {
        Foo foo1 = Foo.A | Foo.B | Foo.C;
        Foo foo2 = Foo.C | Foo.B;

        Foo firstInfoo1 = foo1.AsList()[0];
        Foo firstInFoo2 = foo2.AsList()[0];
    }
}

现在firstInfoo1firstInfoo2都是Unknown我不想要的。看到那里的代码应该总是返回索引[1],如下所示:foo1.AsList()[1]

这是个好主意吗?关于错误的任何想法,绑定检查都需要完成。

另外我们来看看foo2,我先添加Foo.C,然后添加Foo.B秒。有什么方法可以从AsList Foo.C而不是Foo.B获得,即第一个按顺序添加。

这可能吗?

感谢帮助。

由于

3 个答案:

答案 0 :(得分:2)

删除未知值,或执行以下操作:

if ((int)sT != 0 && (sT & types) == sT) list.Add(sT);

一些背景:那些OR-ed枚举不像存储器那样存储,它们存储为一个简单的整数,因此.NET不知道如何构造枚举。

答案 1 :(得分:1)

您需要具体排除Foo.Unknown元素,因为0 & x始终为0

if ((sT != Foo.Unknown) && ((sT & types) == sT)) list.Add(sT);

无法保留枚举的顺序。您必须使用其他类型才能执行此操作(List<Foo>?)。

答案 2 :(得分:1)

您的“AsList”实现中有一些要点(如果您打算添加类似的内容) 更多枚举的扩展名:

  1. 您可能不会消除List [0],但枚举项目等于0  当且仅当枚举具有[标志]属性
  2. 删除所有别名

    是个好主意

    例如,对于某些枚举:

  3. public enum Quantity {
      Zero = 0,  // <- You probably want to preserve it
      One = 1,
      Many = 2,
      ALotOf = 2 // <- You'd rather eliminate this alias
    }
    

    另一个

    [Flags]
    public enum Rigths {
      None = 0,          // <- You don't need it
      CanRead = 1,
      CanWrite = 2,
      CanDelete = 4,
      CanErase = 4,      // <- This alias is of no use
      CanEliminate = 4   // <- And this alias is of no use as well
    }
    

    可能的解决方案是

      public static class Extensions {
        private static long EnumToLong(Object value) {
          if (Object.ReferenceEquals(null, value))
            return 0;
    
          Type type = value.GetType();
    
          if (!type.IsEnum)
            return 0;
    
          Type baseType = Enum.GetUnderlyingType(type);
    
          if (baseType == typeof(long))
            return (long) (value);
          else if (baseType == typeof(ulong))
            return (long) ((ulong) value);
          else if (baseType == typeof(uint))
            return (long) ((uint) value);
          else if (baseType == typeof(int))
            return (long) ((int) value);
          else if (baseType == typeof(short))
            return (long) ((short) value);
          else if (baseType == typeof(ushort))
            return (long) ((ushort) value);
          else if (baseType == typeof(byte))
            return (long) ((byte) value);
          else if (baseType == typeof(sbyte))
            return (long) ((sbyte) value);
    
          return 0;
        }
    
        private static List<T> CoreAsList<T>(Enum value) {
          // Has [Flags] attribute?
          Boolean hasFlagAttribute = false;
    
          Object[] attrs = typeof(T).GetCustomAttributes(true);
    
          for (int i = attrs.GetLowerBound(0); i <= attrs.GetUpperBound(0); ++i)
            if (attrs[i] is FlagsAttribute) {
              hasFlagAttribute = true;
    
              break;
            }
    
          List<T> result = new List<T>();
          HashSet<long> hs = new HashSet<long>();
    
          foreach (var item in Enum.GetValues(typeof(T))) {
            long v = EnumToLong(item);
            long all = EnumToLong(value);
    
            if (hs.Contains(v))
              continue;
    
            hs.Add(v);
    
            if ((all & v) == v)
              if (Enum.IsDefined(typeof(T), item))
                if (!((v == 0) && (hasFlagAttribute)))
                  result.Add((T) item);
          }
    
          return result;
        }
    
        /// <summary>
        /// You extension
        /// </summary>
        public static List<Foo> AsList(this Foo types) {
          return CoreAsList<Foo>(types);
        }
      }
    

    至于订单,你不能保留它。如您所见,枚举实际上是一个整数:

      [Flags]
      public enum Options: long { // or byte, int, uint, short…
        Option1 = 0,
        Option2 = 1,
        OptionN = 1024  
      }
    

    什么时候你做的事情

    Options a = b | c 
    

    你因为整数而失去了订单

    b | c == c | b