我怎么知道枚举中的物品?
在这个问题中 ,我在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; }