2016-09-27 43 views
0

我从根本上误解了HasFlags的工作原理吗?我不明白为什么这段代码失败了。为什么我的[Flag]枚举验证失败?

此代码取值并确定它是否是我的枚举值的有效组合。

Enum值的两个子组由ORing其他成员标识:JustTheMonths和Exclusives。 JustTheMonths是在Enum中声明的,而Exclusives是在验证方法中构建的。

当我将1或2(未分配或未知)传递给此方法时,它将它们正确地标识为有效 - 独占,但不是JustTheMonths的成员。

但是,当我将4传递给此代码时,它正确地将其识别为整个集合的成员,但将其错误地标识为子集合JustTheMonths的成员。

我在这里做错了什么?为什么我的代码认为4是(8 | 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096 | 8172 | 16344)的成员?

private void Form1_Load(object sender, EventArgs e) 
    { 
     FloweringMonth test = FloweringMonth.NotApplicable; 

     if (IsValidFloweringMonthValue((int)test)) 
     { 
      System.Diagnostics.Debug.WriteLine("Valid"); 
     } 
     else 
     { 
      System.Diagnostics.Debug.WriteLine("Not Valid"); 
     } 
    } 

    [Flags] 
    public enum FloweringMonth 
    { 
     Unassigned = 1, Unknown = 2, NotApplicable = 4, 
     Jan = 8, Feb = 16, Mar = 32, Apr = 64, May = 128, Jun = 256, 
     Jul = 512, Aug = 1024, Sep = 2048, Oct = 4086, Nov = 8172, Dec = 16344, 
     JustMonths = (Jan | Feb | Mar | Apr | May | Jun | Jul | Aug | Sep | Oct | Nov | Dec) 
    } 

    public static bool IsValidFloweringMonthValue(int value) 
    { 
     FloweringMonth incoming = (FloweringMonth)value; 

     FloweringMonth AllVals = FloweringMonth.Unassigned | FloweringMonth.Unknown | 
      FloweringMonth.NotApplicable | FloweringMonth.Jan | FloweringMonth.Feb | 
      FloweringMonth.Mar | FloweringMonth.Apr | FloweringMonth.May | 
      FloweringMonth.Jun | FloweringMonth.Jul | FloweringMonth.Aug | 
      FloweringMonth.Sep | FloweringMonth.Oct | FloweringMonth.Nov | FloweringMonth.Dec; 

     // does the incoming value contain any enum values from AllVals? 
     bool HasMembersOfAll = AllVals.HasFlag(incoming); 
     if (!HasMembersOfAll) return false; 

     // does the incoming value contain any enum values from JustTheMonths? 
     bool HasMembersOfMonths = FloweringMonth.JustMonths.HasFlag(incoming); 

     // does it contain any enum values from the set of three exclusive values? 
     FloweringMonth Exclusives = (FloweringMonth.Unassigned | 
      FloweringMonth.Unknown | FloweringMonth.NotApplicable); 
     bool HasMembersOfExclusives = Exclusives.HasFlag(incoming); 

     // an exclusive value cannot be mixed with any month values 
     if (HasMembersOfMonths && HasMembersOfExclusives) return false; // bad combo 

     // an exclusive value cannot be mixed with other exclusive values 
     if (incoming.HasFlag(FloweringMonth.Unassigned) && 
      incoming.HasFlag(FloweringMonth.Unknown)) return false; 
     if (incoming.HasFlag(FloweringMonth.Unassigned) && 
      incoming.HasFlag(FloweringMonth.NotApplicable)) return false; 
     if (incoming.HasFlag(FloweringMonth.Unknown) && 
      incoming.HasFlag(FloweringMonth.NotApplicable)) return false; 

     return true; 
    } 
+0

从https://msdn.microsoft.com/en-us/library/system.enum(v=vs.110).aspx: 。 。定义两个幂的枚举常量,即1,2,4,8等等。这意味着组合枚举常量中的各个标志不会重叠。 –

+0

@ m-y嗯,没有。编译器在没有显式值的情况下分配'0,1,2,3,4,...'。 Flags属性不会改变这种行为。 –

+0

@KennethK .:我纠正了,你是对的。 –

回答

2

您的2的倍数不正确。 4086应该是4096,8172应该是8192等...

+2

为了避免这种错误,请使用两次幂。例如:未分配= 2^0,未知= 2^1,不适用= 2^2,Jan = 2^3,Feb = 2^4,... ... – kurakura88

+0

上帝。我怎么会想念那个。谢谢!不要在深夜做自己的数学... @ kurakura88,好主意。 –

+0

@ kurakura88 C#没有PowerOf运算符;你的建议(“^”)是一个按位运算符。你给了我一个不错的微妙的错误,这使得一些退步。需要使用Math.Pow静态方法。你可能想编辑你的答案,我刚刚高兴地复制到我的代码中:-) –

2

以下@dukedukes回答,问题是在那里你的倍数2是关闭的。

避免此错误的一种方法是在右侧使用bitwise操作。

[Flags] 
enum Months 
{ 
    January = 1 << 3, // 8 
    February = 1 << 4, // 16 
    March = 1 << 5, // 32 
} 
+2

你的意思是'1 << 0'和'1 << 1'和'1 << 2'? – zerkms

+0

@zerkms,是的。我做到了。谢谢。我暂时没有使用过这种模式。 – Dennis