Перечисления C# - проверьте флаги против маски
У меня есть следующие флаги перечисления:
[Flags]
private enum MemoryProtection: uint
{
None = 0x000,
NoAccess = 0x001,
ReadOnly = 0x002,
ReadWrite = 0x004,
WriteCopy = 0x008,
Execute = 0x010,
ExecuteRead = 0x020,
ExecuteReadWrite = 0x040,
ExecuteWriteCopy = 0x080,
Guard = 0x100,
NoCache = 0x200,
WriteCombine = 0x400,
Readable = (ReadOnly | ReadWrite | ExecuteRead | ExecuteReadWrite),
Writable = (ReadWrite | WriteCopy | ExecuteReadWrite | ExecuteWriteCopy)
}
Теперь у меня есть экземпляр enum, который мне нужно проверить, доступен ли он для чтения. Если я использую следующий код:
myMemoryProtection.HasFlag(MemoryProtection.Readable)
Он всегда возвращает false в моем случае, потому что я думаю, что HasFlag проверяет, есть ли у него каждый флаг. Мне нужно что-то элегантное, чтобы избежать этого:
myMemoryProtection.HasFlag(MemoryProtection.ReadOnly) ||
myMemoryProtection.HasFlag(MemoryProtection.ReadWrite) ||
myMemoryProtection.HasFlag(MemoryProtection.ExecuteRead) ||
myMemoryProtection.HasFlag(MemoryProtection.ExecuteReadWrite)
Как мне это сделать?
3 ответа
Вы можете перевернуть условие и проверить, является ли составной enum
имеет флаг, а не проверяет флаг для составного, как это:
if (MemoryProtection.Readable.HasFlag(myMemoryProtection)) {
...
}
Вот пример:
MemoryProtection a = MemoryProtection.ExecuteRead;
if (MemoryProtection.Readable.HasFlag(a)) {
Console.WriteLine("Readable");
}
if (MemoryProtection.Writable.HasFlag(a)) {
Console.WriteLine("Writable");
}
Это печатает Readable
,
Попробуйте побитовые операторы:
[TestMethod]
public void FlagsTest()
{
MemoryProtection mp = MemoryProtection.ReadOnly | MemoryProtection.ReadWrite | MemoryProtection.ExecuteRead | MemoryProtection.ExecuteReadWrite;
MemoryProtection value = MemoryProtection.Readable | MemoryProtection.Writable;
Assert.IsTrue((value & mp) == mp);
}
Да, hasFlag
проверяет, установлено ли каждое битовое поле (флаг).
Вместо того, чтобы лечить Readable
как совокупность всех защит, которые включают Read
во имя, вы можете перевернуть композицию? Например
[Flags]
private enum MemoryProtection: uint
{
NoAccess = 0x000,
Read = 0x001,
Write = 0x002,
Execute = 0x004,
Copy = 0x008,
Guard = 0x010,
NoCache = 0x020,
ReadOnly = Read,
ReadWrite = (Read | Write),
WriteCopy = (Write | Copy),
// etc.
NoAccess = 0x800
}
Затем вы можете написать код:
myMemoryProtection.HasFlag(MemoryProtection.Read)