2023-05-03 11:06:20 +02:00
== Why is this an issue?
2023-06-06 13:48:40 +02:00
An enumeration can be decorated with the https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute[FlagsAttribute] to indicate that it can be used as a https://en.wikipedia.org/wiki/Bit_field[bit field]: a set of flags, that can be independently set and reset.
2020-06-30 12:48:07 +02:00
2023-06-06 13:48:40 +02:00
For example, the following definition of the day of the week:
2020-06-30 12:48:07 +02:00
2022-02-04 17:28:24 +01:00
[source,csharp]
2020-06-30 12:48:07 +02:00
----
[Flags]
2023-06-06 13:48:40 +02:00
enum Days
{
Monday = 1, // 0b00000001
Tuesday = 2, // 0b00000010
Wednesday = 4, // 0b00000100
Thursday = 8, // 0b00001000
Friday = 16, // 0b00010000
Saturday = 32, // 0b00100000
Sunday = 64 // 0b01000000
}
----
allows to define special set of days, such as `WeekDays` and `Weekend` using the `|` operator:
[source,csharp]
----
[Flags]
enum Days
{
// ...
None = 0, // 0b00000000
Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday, // 0b00011111
Weekend = Saturday | Sunday, // 0b01100000
All = Weekdays | Weekend // 0b01111111
}
----
These can be used to write more expressive conditions, taking advantage of https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators[bitwise operators] and https://learn.microsoft.com/en-us/dotnet/api/system.enum.hasflag[Enum.HasFlag]:
[source,csharp]
----
var someDays = Days.Wednesday | Days.Weekend; // 0b01100100
someDays.HasFlag(Days.Wednesday); // someDays contains Wednesday
var mondayAndWednesday = Days.Monday | Days.Wednesday;
someDays.HasFlag(mondayAndWednesday); // someDays contains Monday and Wednesday
someDays.HasFlag(Days.Monday) || someDays.HasFlag(Days.Wednesday); // someDays contains Monday or Wednesday
someDays & Days.Weekend != Days.None; // someDays overlaps with the weekend
someDays & Days.Weekdays == Days.Weekdays; // someDays is only made of weekdays
----
2023-06-07 15:41:34 +02:00
Consistent use of `None` in flag enumerations indicates that all flag values are cleared. The value 0 should not be used to indicate any other state since there is no way to check that the bit `0` is set.
2023-06-06 13:48:40 +02:00
[source,csharp]
----
[Flags]
enum Days
{
Monday = 0, // 0 is used to indicate Monday
Tuesday = 1,
Wednesday = 2,
Thursday = 4,
Friday = 8,
Saturday = 16,
Sunday = 32,
Weekdays = Monday | Tuesday | Wednesday | Thursday | Friday,
Weekend = Saturday | Sunday,
All = Weekdays | Weekend
}
var someDays = Days.Wednesday | Days.Thursday;
someDays & Days.Tuesday == Days.Tuesday // False, because someDays doesn't contains Tuesday
someDays & Days.Monday == Days.Monday // True, even though someDays doesn't contains Monday!
someDays.HasFlag(Days.Monday) // Same issue as above
----
== How to fix it
=== Code examples
==== Noncompliant code example
[source,csharp,diff-id=1,diff-type=noncompliant]
----
[Flags]
2020-06-30 12:48:07 +02:00
enum FruitType
{
Void = 0, // Non-Compliant
Banana = 1,
Orange = 2,
Strawberry = 4
}
----
2023-06-06 13:48:40 +02:00
==== Compliant solution
2020-06-30 12:48:07 +02:00
2023-06-06 13:48:40 +02:00
[source,csharp,diff-id=1,diff-type=compliant]
2020-06-30 12:48:07 +02:00
----
[Flags]
enum FruitType
{
None = 0, // Compliant
Banana = 1,
Orange = 2,
Strawberry = 4
}
----
2021-09-20 15:38:42 +02:00
2023-06-06 13:48:40 +02:00
== Resources
=== Documentation
* https://learn.microsoft.com/en-us/dotnet/api/system.flagsattribute[FlagsAttribute]
* https://en.wikipedia.org/wiki/Bit_field[Bit field]
* https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/bitwise-and-shift-operators[Bitwise and shift operators (C# reference)]
* https://learn.microsoft.com/en-us/dotnet/api/system.enum.hasflag[Enum.HasFlag(Enum) Method]
=== Articles & blog posts
2021-09-20 15:38:42 +02:00
2023-06-06 13:48:40 +02:00
* https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms229062(v=vs.100)[Designing Flags Enumerations]
2021-09-20 15:38:42 +02:00
2023-06-06 13:48:40 +02:00
include::../rspecator.adoc[]