В этот вопрос , я использую оператор xor между enum
с атрибутом [Flags]
следующим образом:
[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,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
. Почему и как решить?