
В этой публикации я постараюсь вкратце рассказать о типе перечисления в C#, применении его в качестве флагов, а так же о том, как можно упростить их рисование в инспекторе Unity.
Что такое Enum?
Перечисления являются значимым типом в языке C#, состоящим из набора констант. Для его объявления используется ключевое слово enum. Каждый перечислитель имеет целочисленное значение. Первый по умолчанию 0, а последующие увеличиваются на 1.
enum Color { Red, // 0 Green, // 1 Blue // 2 }
Для переопределения значений можно воспользоваться инициализаторами.
enum Color { Red = 1, Green = 2, Blue = 3 }
Каждый тип перечисления имеет базовый тип, в роли которого может выступать любой целочисленный тип кроме char (по умолчанию используется int). Его также можно указать явно.
enum Color : byte { Red = 1, Green = 2, Blue = 3 }
Флаги
Порой возникает необходимость наделить сущность рядом свойств. Можно объявить несколько полей или завести список, но иногда достаточно одного перечисления. Для использования перечисления в качестве флагов следует добавить специальный атрибут System.FlagsAttribute. При этом требуется явная инициализация значений, каждое из которых возводится в степень.
[System.FlagsAttribute] enum Color : byte { None = 0, Red = 1, // 2 ^ 0 Green = 2, // 2 ^ 1 Blue = 4 // 2 ^ 2 }
С помощью побитовой операции OR можно объединять элементы перечисления, а используя метод HasFlag(Enum) проверять наличие битовых полей в экземпляре.
var color = Color.Red | Color.Green | Color.Blue; var hasFlag = color.HasFlag(Color.Red | Color.Green); // True
С помощью побитовой операции AND можно также осуществлять проверки.
var aColor = Color.Red | Color.Green; var bColor = Color.Green | Color.Blue; // Проверка наличия битовых полей var contains = (aColor & bColor) == bColor; // False // Проверка пересечения битовых полей var overlaps = (aColor & bColor) != 0; // True
Перечисления в Unity
Для примера возьмём нижеприведённый код.
using UnityEngine; public enum Color { Red, Green, Blue } public class Example : MonoBehaviour { public Color Color; }
Встроенные средства Unity позволяют отображать перечисления в виде выпадающего списка.

К сожалению, редактор не умеет автоматически рисовать перечисления в виде флагов. Для этих целей требуется переопределение инспектора, что далеко не всегда удобно. Но можно пойти на хитрость и переопределить рисование перечислений глобально. Для начала модифицируем пример.
using System; using UnityEngine; [Flags] public enum Color { Red = 1, Green = 2, Blue = 4 } public class Example : MonoBehaviour { public Color Color; }
Далее нужно реализовать свой PropertyDrawer. Если сериализуемое свойство имеет атрибут Flags, то для рисования будем использовать метод EditorGUI.MaskField, а в противном случае стандартный метод EditorGUI.PropertyField. Также следует учесть, что свойство может являться элементом массива. Приведённый ниже код следует поместить в папку с именем Editor.
[CustomPropertyDrawer(typeof(Enum), true)] public sealed class EnumPropertyDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { using (new EditorGUI.PropertyScope(position, label, property)) { if (HasEnumFlagsAttribute()) { var intValue = EditorGUI.MaskField(position, label, property.intValue, property.enumDisplayNames); if (property.intValue != intValue) { property.intValue = intValue; } } else { EditorGUI.PropertyField(position, property, label); } } bool HasEnumFlagsAttribute() { var fieldType = fieldInfo.FieldType; if (fieldType.IsArray) { var elementType = fieldType.GetElementType(); return elementType.IsDefined(typeof(FlagsAttribute), false); } return fieldType.IsDefined(typeof(FlagsAttribute), false); } } }
Теперь поле корректно отображается в инспекторе для любого Enum типа.

В дополнение к определённым значениям перечисления редактор добавляет ещё два:
- Nothing — имеет целочисленное значение 0;
- Everything — имеет целочисленное значение -1.
