[Flags]属性到底是什么?

30

应用 [Flags] 到枚举类型有什么实际作用?

我知道它会修改 Enum.ToString 的行为,但除此之外还有其他作用吗?(例如:不同的编译器或运行时行为等)


编辑: 是的,我知道它 文档化了 枚举类型是用于按位标志的事实,并且将其应用于位标志更具逻辑性。我更想了解的是具体的行为变化,而不是一般的编程实践。


2
请查看http://msdn.microsoft.com/en-us/library/ms229062.aspx。 - SQLMenace
1
@SQLMenace:这只是说明了我应该何时应用它以及如何编写我的代码,而不是它是否改变了任何行为。:\ - user541686
3
+1 我已经问过自己很多次这个问题。 - Chris Marisic
1
我想看看@Eric Lippert 对此的评论。 - Dave Ziegler
6个回答

30

根据MSDN文章的内容:

值得注意的是,当指定标志时,Parse和Format方法具有高级功能。

同样,Parse方法可以成功地将像刚才展示的逗号分隔字符串解析为正确的数值。


1
+1 看起来是目前为止最好的答案。我不知道它会改变 Parse 的行为... - user541686

17
请见David M. Kean在这里的帖子。这似乎是一种语言交互问题:
虽然C#允许用户在没有FlagsAttribute的情况下对枚举执行位操作,但Visual Basic不允许这样做。因此,如果您将类型公开给其他语言,则标记具有FlagsAttribute的枚举是一个好主意;它也清楚地表明枚举成员旨在一起使用。
问候,
大卫

+1 很棒(而且出乎意料)的回答。 :) (虽然我必须承认,对我来说,“.NET”基本上只是同一语言的不同形式。尽管如此,这仍然是一个很好的答案。) - user541686
如果您将该帖子的内容复制到答案中,那么您的答案将更好。 - Daniel Pryden
嗯...我刚刚检查了一下,VB并没有像这篇文章所暗示的那样将[flag]枚举自动分配为2的幂。它通常是通过加1来递增它们的。 - Brian MacKay

10
以下是具体的行为差异列表:
- 使用 [flags] 设置枚举为 None 会清除所有标志。 - 只有在存在该属性时,HasFlags 方法才有效。 - 正如 Devio 所说,它会改变 Parse 和 Format 方法的功能。他链接了 this article。显然,它还影响调试器中显示的内容。 - 我认为 [flags] 可能会对 Web 服务中的代码生成产生影响,但看起来并非如此。 - 明确地说,在任何枚举上都允许位运算,无论是否使用 [flags]。但使用它是最佳实践。
更多细节请参考:http://msdn.microsoft.com/en-us/library/ms229062.aspx

5

如果你问它在底层做了什么,据我所知,它只改变了ToString()方法,没有其他操作。

.Net 4下有HasFlags方法来检查特定的标志。如果我正确理解MSDN,你需要使用flags属性才能使用此方法。但我没有尝试过。


1
实际上,我使用的其中一种用途是指示多个状态。这是对评估测试结果的某些代码的简化。测试可以是“Ok”,也可能有多个原因导致不“Ok”。这样做的好处是,我只需要一个方法来评估测试的“Ok-ness”,并且该方法能够用一个返回值指示所有可能的失败条件。这可能不是最佳设计,但在这种情况下它有效。
[Flags]
public enum ResultStatusEnum
{
    Ok = 0x1,
    SampleInvalid = 0x2,
    DirectionInvalid = 0x4,
    TestIsNotValid = 0x8
}

你可以这样设置:

ResultStatusEnum res = ResultStatusEnum.SampleInvalid | ResultStatusEnum.DirectionInvalid;

缺点是检查枚举值变得繁琐。这种方法不一定有效:
res == ResultStatusEnum.Ok

你必须这样做来检查:

ResultStatusEnum.SampleInvalid == (res & ResultStatusEnum.SampleInvalid)

在这种情况下,使用ResultStatusEnum.Ok & ResultStatusEnum.SampleInvalid是不合逻辑的,但我只是确保我没有在枚举中使用这种情况。

是的,但如果没有相应的装饰,其他语言可能无法正确处理枚举。如果全部都是C#,那么这并不重要。但当我看到它时,我期望看到这种用法。如果没有它,我就不会期望看到位运算的使用。因此,这对于可读性很有帮助。 - Tim Coker
取决于你所说的“处理”是什么意思。它们肯定可以以同样的方式对它们进行位运算,但是是否首先允许它们似乎是一个问题,根据Charles发布的内容 - user541686

0

Flags 提供了使用枚举类型存储多个值的选项。

考虑这样一种情况:您想要在不同的场景中使用复选框,但不想在数据库中创建不同的列。如果您有 20 个复选框,则必须创建 20 个带有布尔值的列。但是使用 flags,您可以创建一个列,并使用该值将其存储在该列中。在控制台中运行此示例以更好地理解它。

class Program
{
    static void Main(string[] args)
    {
        //Set the features that you require for car. Consider it as checked in the UI.
        CarFeatures carFeatures = CarFeatures.AC | CarFeatures.Autopilot| CarFeatures.Sunroof;

        //Do the backend logic
        if (carFeatures.HasFlag(CarFeatures.Autopilot))
        {
            //Show Autopilot cars
        }
        //See the what carfeatures are required
        Console.WriteLine(carFeatures);
        //See the integer value of the carfeatures
        Console.WriteLine((int)carFeatures);
        Console.ReadLine();
    }
}

[Flags]
public enum CarFeatures
{
    AC=1,
    HeatedSeats= 2,
    Sunroof= 4,
    Autopilot= 8,
}

不同的组合总是会给你一个独特的数字,C#会跟踪这个数字以找到所有被标记的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接