如何从[Flag]枚举属性中检索值?

use*_*er1 6 c# enums flags

说我有一个enum这样的定义:

[Flags]
public enum LogLevel
{
    None = 1,
    Pages = 2,
    Methods = 4,
    Exception =8
}
Run Code Online (Sandbox Code Playgroud)

和一个类似的类:

public static class Log
{
    public static LogLevel Level = LogLevel.Methods | LogLevel.Pages;

    public static void EnterPage([CallerFilePath]string filePath = "")
    {
        if (Level == //What value here to check if Level includes Pages?)
        {
             //Log
        }
    }
Run Code Online (Sandbox Code Playgroud)

我需要等于什么值Level来检查枚举是否包含Pages

Mat*_*zer 6

首先,标志必须具有一个None = 0值,因为否则就无法表示0掩码(即,没有value)。

修复它之后,您可以使用Enum.HasFlag或按位&运算符检查某些枚举值是否在给定的标志中:

Level.HasFlag(LogLevel.Pages);
Run Code Online (Sandbox Code Playgroud)

...要么:

(Level & LogLevel.Pages) == LogLevel.Pages
Run Code Online (Sandbox Code Playgroud)

最后,当实现标志枚举时,枚举标识符通常以复数形式表示。就您而言,您应该重构LogLevelLogLevels

为什么&

每个枚举值代表完整掩码中的一位。例如,None将为0,但也可以将其表示为0, 0, 0中每个0可能的枚举值之一LogLevels。当您提供类似的口罩时LogLevels.Pages | LogLevels.Methods,则口罩为1, 1, 0

为了检查Pages掩码中是否包含掩码,可以使用逻辑将掩码与可能的枚举值之一进行比较:

1, 1, 0 (LogLevels.Pages | LogLevels.Methods)
1, 0, 0 AND (LogLevels.Pages)
--------
1, 0, 0 
Run Code Online (Sandbox Code Playgroud)
  • 1和1(true和true == true)
  • 1和0(对与错==否)
  • 0和0(false和false == false)。

整个AND就像隔离测试的枚举值。如果生成的掩码等于枚举值,则该掩码包含枚举值。

一些OP关注

OP在一些评论中说:

只是一个零值问题。此处表明您不能在按位AND操作中使用None枚举常量来测试标志,因为结果始终为零。这是否意味着如果我的值为0,则我不能使用&并且必须使用HasFlag?

None(即0)不会成为掩码的成员,因为0 不存在。生成遮罩时,您使用的是OR |逻辑运算符,最终,它是加法运算符。

想一想1 + 0 == 1。您是否认为有可能0在内部1

实际上,该None = 0值需要能够表示并清空掩码。

最后,HasFlagAND对您来说不是一个神奇的解决方案,而是一种更具可读性和封装性的执行所谓的的方式AND