I haven't really used bitwise enums before, and I just want to make sure my testing is correct. I am most interested in testing for the values None and All. We receive data from a webservice that utilises this enum to categorise certain pieces of the data. Given that, I am assuming that nether None nor All would ever be combined with any other value.
Given the following bitwise enum definition;
[System.FlagsAttribute()]
public enum TrainingComponentTypes : int
{
None = 0,
AccreditedCourse = 1,
Qualification = 2,
Unit = 4,
SkillSet = 8,
UnitContextualisation = 16,
TrainingPackage = 32,
AccreditedCourseModule = 64,
All = 127,
}
I read the following quote on this MSDN site about FlagAttributes;
Use None as the name of the flag нумерованная константа, значение которой нуль. Вы не можете использовать None нумерованная константа в побитовом И операция для проверки флага, потому что результат всегда равен нулю. Однако, вы можете выполнить логический, а не побитовое сравнение между числовое значение и None перечисленные константа, чтобы определить, есть ли какие-либо биты в числовом значении.
Относится ли логическое сравнение в этом случае к обычному тесту на равенство для перечислений? Например:
TrainingComponentTypes tct = TrainingComponentTypes.None;
if (tct == TrainingComponentTypes.None)
{ ... }
Для побитового сравнения я выполняю следующее:
TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification | TrainingComponentTypes.TrainingPackage;
Assert.IsTrue((tct & TrainingComponentTypes.AccreditedCourse) == TrainingComponentTypes.AccreditedCourse, "Expected AccreditedCourse as part the enum");
Assert.IsFalse((tct & TrainingComponentTypes.SkillSet) == TrainingComponentTypes.SkillSet, "Found unexpected SkillSet as part the enum");
Наконец, при тестировании для всех я пробовал как логическое, так и побитовое сравнение, и оба они возвращают одно и то же. . Должен ли я использовать здесь один вместо другого? Например;
TrainingComponentTypes tct = TrainingComponentTypes.All;
Assert.IsTrue((tct & TrainingComponentTypes.All) == TrainingComponentTypes.All, "Expected All as part the enum");
Assert.IsTrue((tct) == TrainingComponentTypes.All, "Expected All as part the enum");
// The follow also pass the assertion for a value of All
Assert.IsTrue((tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification, "Expected Qualification as part the enum");
Assert.IsTrue((tct & TrainingComponentTypes.TrainingPackage) == TrainingComponentTypes.TrainingPackage, "Expected TrainingPackage as part the enum");
Итак, вкратце, я хотел бы узнать следующее о побитовых перечислениях:
Спасибо, Крис
Является ли мое понимание логического сравнения правильным, учитывая мой пример выше?
Да, логический в этом контексте означает операторы равенства и неравенства.
Является ли способ выполнения побитового сравнения правильным?
Да, но есть более простой способ: Enum.HasFlag
. Например:
tct.HasFlag(TrainingComponentTypes.Qualification)
вместо:
(tct & TrainingComponentTypes.Qualification) == TrainingComponentTypes.Qualification
Как правильно обрабатывать значение «Все» (побитовое или логическое). Я не уверен, получим ли мы когда-либо значение, в котором All было бы объединено с другими типами TrainingComponentTypes. Я не могу понять, почему мы это сделаем, но тогда, вы никогда не знаете?
Я думаю, что лучше определить All
в самом enum
как побитовое ИЛИ всех его частей. Но вы увидите, что люди делают это в обоих направлениях.
Прав ли я, если предположить, что операторы switch в основном не должны использоваться для побитовых перечислений (если ни один из них не является особым случаем и требует логического сравнения)?
Нет , не за что. Не стесняйтесь использовать их в switch
утверждениях. Значения case
должны быть константами, но они могут быть выражениями и проверяться на равенство. Компилятор скажет вам, если вы делаете что-то глупое, например, попробуйте дважды использовать одно и то же значение case
.
1 и 2 - да, однако есть способ сделать его немного легче для чтения:
TrainingComponentTypes tct = TrainingComponentTypes.AccreditedCourse | TrainingComponentTypes.Qualification;
Assert.IsTrue(tct.HasFlag(TrainingComponentTypes.AccreditedCourse), "Expected AccreditedCourse as part the enum");
3 - Я не уверен, что вам вообще нужна вся ценность. Я бы удалил его.
4 - Да, оператор switch обычно не имеет смысла для перечислений Flags.