Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

The [Flags] attribute in C# is a metadata marker applied to an enum declaration to indicate that its values represent a bit field. It instructs the .NET runtime to treat the enumeration as a collection of composable bitwise flags rather than mutually exclusive scalar values. Applying this attribute fundamentally alters how the System.Enum.ToString() method formats the enumeration. Without [Flags], calling ToString() on a bitwise-combined enum value that does not have an exact named constant match returns its raw numeric integer. With [Flags], the runtime evaluates the active bits and returns a comma-separated string of the corresponding enum names. Note: The [Flags] attribute only affects string formatting. Methods like Enum.Parse and Enum.TryParse natively support parsing comma-separated strings into bitwise-combined integers regardless of whether the attribute is present.

Value Assignment Mechanics

For a bit field enumeration to function correctly, the underlying numeric values must be defined as powers of two (1, 2, 4, 8, 16, etc.). This ensures that each value occupies exactly one distinct bit in the underlying binary representation. The bitwise left-shift operator (<<) is the standard convention for defining these values, as it visually maps to the bit position.
[Flags]
public enum SystemPermissions : byte
{
    None = 0,           // 00000000
    Read = 1 << 0,      // 00000001 (1)
    Write = 1 << 1,     // 00000010 (2)
    Execute = 1 << 2,   // 00000100 (4)
    Modify = 1 << 3     // 00001000 (8)
}

Runtime Behavior Changes

String Formatting (ToString) When multiple flags are combined, ToString() behavior diverges based on the presence of the [Flags] attribute. To demonstrate this, we must compare two distinct enumerations: one with the attribute and one without.
[Flags]
public enum FlagsPerms { None = 0, Read = 1, Write = 2 }

public enum BasicPerms { None = 0, Read = 1, Write = 2 }

// With [Flags] attribute:
FlagsPerms activeFlags = FlagsPerms.Read | FlagsPerms.Write;
Console.WriteLine(activeFlags.ToString()); 
// Output: "Read, Write"

// Without [Flags] attribute:
BasicPerms activeBasic = BasicPerms.Read | BasicPerms.Write;
Console.WriteLine(activeBasic.ToString()); 
// Output: "3"
Crucial distinction: If the enumeration explicitly defines a composite value (e.g., ReadWrite = Read | Write, which equals 3), ToString() will always output the exact named constant "ReadWrite" instead of "Read, Write" or "3", regardless of the [Flags] attribute.

Bitwise Manipulation Syntax

Because [Flags] enums represent bit fields, they are manipulated using standard bitwise operators rather than arithmetic operators.
SystemPermissions perms = SystemPermissions.None;

// Set a flag (Bitwise OR)
perms |= SystemPermissions.Read;

// Check for a flag (Bitwise AND or Enum.HasFlag)
bool canRead = (perms & SystemPermissions.Read) == SystemPermissions.Read;
bool canReadModern = perms.HasFlag(SystemPermissions.Read);

// Remove a flag (Bitwise AND with Bitwise NOT)
perms &= ~SystemPermissions.Read;

// Toggle a flag (Bitwise XOR)
perms ^= SystemPermissions.Write;
Critical Caveat: Checking for None (0) Because the None value is mathematically 0, bitwise evaluation against it behaves uniquely. The expression value & 0 == 0 is a mathematical tautology. Consequently, calling perms.HasFlag(SystemPermissions.None) or evaluating (perms & SystemPermissions.None) == SystemPermissions.None will always return true, regardless of the current state of perms. To correctly check if an enumeration is completely empty (set to None), you must use direct equality:
// INCORRECT: Always evaluates to true
bool isEmpty = perms.HasFlag(SystemPermissions.None); 

// CORRECT: Checks if the value is exactly 0
bool isEmptyCorrect = perms == SystemPermissions.None; 

Structural Rules

  1. The None Value: Always define a value of 0 named None (or similar). Bitwise operations rely on 0 to represent an empty state (all bits cleared).
  2. Underlying Type Capacity: By default, enums are backed by int (32-bit), allowing up to 32 distinct flags. If more flags are required, the underlying type must be explicitly declared as long or ulong (64-bit).
  3. Signed Types and the Sign Bit: Avoid using signed underlying types (sbyte, short, int, long) if you intend to utilize the highest bit (the sign bit). Setting the sign bit results in a negative numeric value, which complicates bitwise operations and comparisons. Prefer unsigned types (byte, ushort, uint, ulong) when all bits of the underlying type are needed for flags.
Master C# with Deep Grasping Methodology!Learn More