我怎么知道枚举中的项目?

时间:2010-09-20 03:22:05

标签: c# .net generics enums extension-methods

this question中,我在enum[Flags]属性之间使用xor运算符,如下所示:

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

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

flags |= QueryFlag.ByDate;

要删除一个,我对Dan Tao's answer有不同的看法。我正在使用:

flags ^= QueryFlag.ByProduct;

他正在使用:

flags &= ~QueryFlag.ByProduct;

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

a,b         a^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

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

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

可能无法用标记的属性约束T.但即使我删除了这个约束,我也会收到编译错误operator ~ can't be applied to type T。为什么以及如何解决?

2 个答案:

答案 0 :(得分:0)

更好的方法可能是:

return (flags & mask) == mask;

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

return (flags & mask) != 0;

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

对于通用方法,您可以尝试将类型约束为struct。这会将T约束为值类型。

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

答案 1 :(得分:0)

您的错误在于此方法:

public static bool Contains(this QueryFlag flags, QueryFlag flag)
{
   return (flags & (~flag)) != 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))
    // ...