【问题标题】:How can I know items is in the enum?我怎么知道项目在枚举中?
【发布时间】:2010-09-20 03:22:04
【问题描述】:

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;
}

也就是说,如果从flags中删除flags后flags没有改变,我们就知道flags不在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。为什么以及如何解决?

【问题讨论】:

  • 您希望 .Contains(QueryFlag.ByDate | QueryFlag.ByCustomer) 在设置其中一个标志时返回 true,还是只设置两个标志?

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


【解决方案1】:

你的错误在于这个方法:

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

只要flagsany(即至少一个flag 中包含的标志,这就会返回 true,但我认为您想要 all .

应该是:

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

或者,您可以只使用Enum.HasFlag(),它就是这样做的。例如:

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

【讨论】:

  • 哦!我不知道HasFlag 方法!这正是我想要的。谢谢。
【解决方案2】:

更好的方法可能是这样的:

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;
}

【讨论】:

  • 现在我了解您对我的第一个问题的 2 个答案。非常感谢。但是对于第二个问题,写约束where T:int是不正确的,因为int不能是where的约束。
  • 是的。我仍然在考虑类型约束。看来您可以将 struct 指定为约束,它将 T 约束为值类型。请参阅编辑后的答案。
  • 答案仍然是错误的。您不能在 T 类型上使用 &amp;==。我可以谦虚地建议您在发布代码之前尝试编译代码吗?
猜你喜欢
  • 2016-04-17
  • 1970-01-01
  • 2022-11-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-04-19
  • 1970-01-01
  • 2015-12-31
相关资源
最近更新 更多