Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
856 views
in Technique[技术] by (71.8m points)

c# - How can I know items is in the enum?

In this question, I use xor operator between enum with [Flags] attribute as following:

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

To add an QueryFlag, of course we should use | operator.

flags |= QueryFlag.ByDate;

To remove one, I have a different way with Dan Tao's answer. I'm using:

flags ^= QueryFlag.ByProduct;

while he is using:

flags &= ~QueryFlag.ByProduct;

Obviously his answer is correct and easy to understand. I thought I made a mistake. But after a deep thought I got:

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

And now I knew my mistake. ^ is wrong when you try to remove one item which doesn't exist.

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!

But here I got another question: how can I know if q contains one item? Base on Dan Tao's answer I wrote an extension:

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

That is, if flags is not changed after removing flag from flags, we know flag is not in flags! It seems correct when:

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

But in fact:

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

I know the reason why it's false, how can I improve it? It's the first question. The second: I want to make the .Contains generic to more enum with [Flags] attribute.

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

Probably it's impossible to constrain T with attribute marked. But even I remove this constraint I get a compile error which says operator ~ can't be applied to type T. Why and how to resolve?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your error lies in this method:

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

This returns true whenever flags has any (i.e. at least one) of the flags contained in flag, but I think you want all.

It should read:

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

Alternatively, you can just use Enum.HasFlag() which does exactly this. For example:

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

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...