Операции перечисления встроенных флагов в .NET, к сожалению, весьма ограничены. Большую часть времени у пользователей остается на выяснение логики побитовой операции.
В .NET 4 к Enum
был добавлен метод HasFlag
, который помогает упростить код пользователя, но, к сожалению, с ним много проблем.
HasFlag
не является типобезопасным, поскольку принимает любой тип аргумента значения перечисления, а не только данный тип перечисления.
HasFlag
является неоднозначным относительно того, проверяет ли оно, имеет ли значение все или какие-либо из флагов, предоставленных аргументом значения enum. Это все кстати.
HasFlag
довольно медленный, так как требует бокса, который вызывает выделение ресурсов и, следовательно, больше сборщиков мусора.
Отчасти из-за ограниченной поддержки .NET перечислений флагов я написал библиотеку OSS Enums.NET , которая решает каждую из этих проблем и значительно упрощает работу с перечислениями флагов.
Ниже приведены некоторые операции, которые он предоставляет вместе с эквивалентными реализациями, использующими только .NET Framework.
Объединить флаги
.NET flags | otherFlags
Enums.NET flags.CombineFlags(otherFlags)
Удалить флаги
.NET flags & ~otherFlags
Enums.NET flags.RemoveFlags(otherFlags)
Общие флаги
.NET flags & otherFlags
Enums.NET flags.CommonFlags(otherFlags)
Тумблеры
.NET flags ^ otherFlags
Enums.NET flags.ToggleFlags(otherFlags)
Имеет все флаги
.NET (flags & otherFlags) == otherFlags
или flags.HasFlag(otherFlags)
Enums.NET flags.HasAllFlags(otherFlags)
Есть флаги
.NET (flags & otherFlags) != 0
Enums.NET flags.HasAnyFlags(otherFlags)
Получить флаги
.NET
Enumerable.Range(0, 64)
.Where(bit => ((flags.GetTypeCode() == TypeCode.UInt64 ? (long)(ulong)flags : Convert.ToInt64(flags)) & (1L << bit)) != 0)
.Select(bit => Enum.ToObject(flags.GetType(), 1L << bit))`
Enums.NET flags.GetFlags()
Я пытаюсь включить эти улучшения в .NET Core и, возможно, в конечном итоге в полную версию .NET Framework. Вы можете проверить мое предложение здесь .