Ответ
[Flags] — это атрибут в C#, который указывает, что перечисление (enum) должно интерпретироваться как битовая маска (флаги). Это позволяет комбинировать несколько значений перечисления в одной переменной с помощью побитовых операций, что удобно для представления множества состояний или опций.
Основные правила создания:
- Значения должны быть степенями двойки (1, 2, 4, 8...), чтобы каждый флаг занимал уникальный бит.
- Определите значение
None = 0для представления пустого набора флагов. - Можно использовать удобную запись с левым сдвигом:
Read = 1 << 0,Write = 1 << 1.
Пример объявления и использования:
[Flags]
public enum FileAccessPermissions
{
None = 0, // 0b_0000
Read = 1 << 0, // 0b_0001
Write = 1 << 1, // 0b_0010
Execute = 1 << 2, // 0b_0100
Delete = 1 << 3, // 0b_1000
// Можно определять комбинированные значения для удобства
ReadWrite = Read | Write // 0b_0011
}
// Использование: комбинация флагов с побитовым ИЛИ (|)
FileAccessPermissions userPermissions = FileAccessPermissions.Read | FileAccessPermissions.Write;
// Проверка наличия флага (рекомендуемый способ)
if (userPermissions.HasFlag(FileAccessPermissions.Write))
{
Console.WriteLine("Разрешена запись.");
}
// Альтернативная проверка с побитовым И (&)
bool canReadAndWrite = (userPermissions & FileAccessPermissions.ReadWrite) == FileAccessPermissions.ReadWrite;
// Удаление флага с помощью побитового И с инверсией (& ~)
userPermissions = userPermissions & ~FileAccessPermissions.Write;
Важно: Атрибут [Flags] в основном влияет на поведение методов ToString() (который выведет "Read, Write") и Enum.Parse(). Сама битовая арифметика работает и без него, но его использование является хорошей практикой для самодокументируемости кода.
Ответ 18+ 🔞
Смотри, объясню на пальцах, как это работает, а то в документации обычно такую хуйню пишут, что мозги набок выворачивает.
Вот представь себе, что у тебя есть набор лампочек на пульте: одна для чтения, другая для записи, третья для запуска. И тебе надо запомнить, какие из них сейчас горят. Можно, конечно, завести кучу булевых переменных: isReadOn, isWriteOn... Но это же пиздец как неудобно, особенно если лампочек двадцать.
Вот для этого и придумали флаги. По сути, это способ упаковать кучу true/false в одно число, используя биты. Каждый бит в числе — это одна твоя «лампочка».
Как это объявляется? Берёшь обычный enum и вешаешь на него волшебный атрибут [Flags]. Это как сказать компилятору: «Чувак, это не просто список, это битовая маска, не путай».
[Flags]
public enum FileAccessPermissions
{
None = 0, // Всё выключено. 0b_0000
Read = 1 << 0, // Включён самый правый бит. 0b_0001
Write = 1 << 1, // Включён второй бит справа. 0b_0010
Execute = 1 << 2, // Третий бит. 0b_0100
Delete = 1 << 3, // Четвёртый. 0b_1000
// А это просто предустановка для ленивых, чтобы не писать Read | Write каждый раз
ReadWrite = Read | Write // 0b_0011 (и Read, и Write)
}
Видишь эти 1 << 0? Это сдвиг единички влево. Так мы гарантируем, что каждое значение — это степень двойки, то есть в двоичном виде это одна единица и куча нулей. Это важно, чтобы биты не накладывались друг на друга и не создавали пиздец и неразбериху.
Как этим пользоваться? Очень просто.
-
Включить лампочки (добавить флаги): Используешь побитовое ИЛИ (
|).// Даю пользователю права на чтение И запись var permissions = FileAccessPermissions.Read | FileAccessPermissions.Write; // В числах: 0b0001 | 0b0010 = 0b0011 -
Проверить, горит ли конкретная лампочка: Лучше всего через
.HasFlag().if (permissions.HasFlag(FileAccessPermissions.Write)) { Console.WriteLine("Можно писать, чувак!"); }Или, для старых школотеров, через побитовое И (
&):bool canWrite = (permissions & FileAccessPermissions.Write) == FileAccessPermissions.Write; -
Выключить лампочку (убрать флаг): Используешь побитовое И (
&) с инвертированным значением (~).// Отбираем право на запись permissions = permissions & ~FileAccessPermissions.Write; // Стало: 0b0011 & ~0b0010 = 0b0011 & 0b1101 = 0b0001 (осталось только Read)
А зачем вообще этот [Flags]? Без него всё тоже будет работать, битовые операции от этого не сломаются. Но это как ехать на машине с выключенными фарами ночью — можно, но ебанись об столб. Атрибут [Flags] — это твои фары:
- Для других разработчиков: Сразу ясно, что этот
enumзаточен под комбинации. - Для
.ToString(): Без атрибутаpermissions.ToString()вернёт загадочное число3. С атрибутом — понятную строку"Read, Write". Удобно же для логов, ёпта! - Для
.Parse(): Можно будет написатьEnum.Parse<FileAccessPermissions>("Read, Write")и получить правильную комбинацию.
Короче, если тебе нужно хранить набор независимых состояний «включено/выключено» — это твой инструмент. Главное, не забудь степени двойки для значений, а то получится ерунда, а не флаги.