我怎么知道枚举中的物品?

在这个问题中 ,我在enum[Flags]属性之间使用xor运算符如下:

 [Flags] enum QueryFlag { None = 0x1, ByCustomer = 0x2, ByProduct = 0x4, ByDate = 0x8 } QueryFlag flags = QueryFlag.ByCustomer | QueryFlag.ByProduct; 

要添加QueryFlag,我们当然应该使用| 运营商。

 flags |= QueryFlag.ByDate; 

为了删除一个,我对丹涛的回答有不同的看法 。 我正在使用:

 flags ^= QueryFlag.ByProduct; 

他正在使用:

 flags &= ~QueryFlag.ByProduct; 

显然他的回答是正确的,易于理解。 我以为我弄错了。 但经过深思熟虑,我得到了:

 a,ba^b a&(~b) 0,0 0 0 0,1 1 0 //the difference 1,0 1 1 1,1 0 0 

而现在我知道我的错误。 当您尝试删除一个不存在的项时, ^是错误的。

 QueryFlag q = QueryFlag.ByCustomer | QueryFlag.ByDate; //try to remove QueryFlag.ByProduct which doesn't exist in q q ^ QueryFlag.ByProduct //equals to add ByProduct to q, wrong! q & (~QueryFlag.ByProduct) // q isn't changed, remain the original value. correct! 

但是我在这里得到了另一个问题:我怎么知道q包含一个项目? 根据丹涛的回答,我写了一个扩展名:

 public static bool Contains(this QueryFlag flags, QueryFlag flag) { return (flags & (~flag)) != flags; } 

也就是说,如果从标志中删除标志后没有更改标志,我们知道标志不在标志中! 这似乎是正确的:

 (QueryFlag.ByProduct | QueryFlag.ByDate).Contains(QueryFlag.None) //false (QueryFlag.ByProduct | QueryFlag.ByDate).Contains(QueryFlag.ByDate) //true 

但实际上:

 (QueryFlag.ByProduct | QueryFlag.ByDate).Contains(QueryFlag.ByDate | QueryFlag.ByCustomer) //true, but I suppose it's false 

我知道它为什么是假的,我怎么能改进呢? 这是第一个问题。 第二种:我想通过[Flags]属性将.Contains泛化为更多enum

 public static bool Contains(this T flags, T flag) where T : Enum//with [Flags] { return (flags & (~flag)) != flags; } 

可能不可能用标记的属性来约束T. 但即使我删除了这个约束,我得到一个编译错误,表示operator ~ can't be applied to type T 为什么以及如何解决?

您的错误在于此方法:

 public static bool Contains(this QueryFlag flags, QueryFlag flag) { return (flags & (~flag)) != flags; } 

每当flags包含flags包含的任何 (即至少一个flag ,都会返回true,但我认为你想要全部

它应该是:

 public static bool Contains(this QueryFlag flags, QueryFlag flag) { return (flags & flag) == flag; } 

或者,您可以使用Enum.HasFlag()来完成此操作。 例如:

 QueryFlag qf = ...; if (qf.HasFlag(QueryFlag.ByCustomer)) // ... 

更好的方法可能是:

 return (flags & mask) == mask; 

如果在mask中设置的所有标志都在flags中设置,则返回true。

 return (flags & mask) != 0; 

如果在mask中设置的任何标志都在flags中设置,则返回true。

对于generics方法,您可以尝试将类型约束为struct 。 这将T限制为值类型。

 public static bool Contains(this T flags, T mask) where T : struct { return (flags & mask) == mask; }