空旗是一种坏习惯吗?

时间:2016-03-07 09:48:35

标签: c# enums flags anti-patterns

几天前我遇到了一个非常愚蠢的错误。这是由我从第三方库获得的枚举引起的:

[Flags]
public enum MyStatus
{
    OKResponse = 0,
    ResponseTooBig = 1,
    ErrorMessage = 2,
    NoResponse = 4,
    ...
}

我习惯用这种方式检查标志:

if ((status & MyStatus.OKResponse) != 0) {...}

但它不适用于MyStatus.OKResponse,因为它为零。它根本不是一面旗帜,它缺少所有旗帜。当然,当我发现错误时,我意识到OKResponse是唯一的非错误状态,所以它实际上意味着“没有错误,没有标志”。但是,我真的不觉得这很明显。

将标志枚举为0中的值之一定义0是一个坏习惯吗?推荐的方式是什么?检查标志的最佳方法是什么,也可以使用“无标志”标志?

2 个答案:

答案 0 :(得分:6)

  

将标志枚举中的值定义为0是一个坏习惯吗?

不,相反,正如评论所说,通常使用0作为给定标志的值,如果没有为第一个标记分配不同的值,则枚举将默认为给定的价值。正如其他人在评论中所说的那样,使用Enum.None作为枚举的第一个值也很常见,这使得您的意图更清晰,其他人也可以阅读代码。

  

推荐的方式是什么?

没有一种方法可以做到,但我通常喜欢使用简洁的Enum.HasFlag方法:

void Main()
{
    var status = MyStatus.ResponseTooBig | MyStatus.NoResponse;
    if (status.Equals(MyStatus.OKResponse))
        Console.WriteLine("Status is OKResponse");
    else 
        Console.WriteLine($"Has NoResponse?: {status.HasFlag(MyStatus.NoResponse)}");
}

答案 1 :(得分:1)

虽然在枚举中实际定义0值是个好主意,但它代表OK是一个非常糟糕的主意,因为0是默认值,它是唯一可以隐式转换为枚举的特殊整数,因此可以很容易地进行转换:

MyStatus status = 0;

因此,0值的实际定义不是问题,但最好让它代表None枚举FlagsInvalid正常枚举的价值。

此外,当成员可以合并时,应使用Flags枚举,但从您的示例看,它们似乎是互斥的。

所以我说enum的设计很糟糕,因为实际上,任何响应都有一个OK标志,这肯定是Flags枚举的错误,如果你不能改变定义,唯一的方法是明确检查状态是否等于OKResponse

if (status == MyStatus.OKResponse)