c# - 如何防止枚举值的按位或组合?

标签 c# enums flags

我知道您可以使用 FlagsAttribute 指示编译器使用位域进行枚举。

有没有办法指定枚举值不能与按位或组合?

例子:

enum OnlyOneOption
{
   Option1,
   Option2,
   ...
}

在这个例子中,没有什么可以阻止开发人员编写 OnlyOneOption.Option1 | OnlyOneOption.Option2。如果可能的话,我想在编译时禁止它。

最佳答案

编译时检查

最近,Eric Lippert(他在 Microsoft 期间从事 C# 编译器工作的人之一)blogged关于他对 C# 的十大遗憾,排名第四

In C#, an enum is just a thin type-system wrapper over an underlying integral type. All operations on enums are specified as actually being operations on integers, and the names of enum values are like named constants.

所以原则上,你不能让编译器阻塞

OnlyOneOption option = OnlyOneOption.Option1 | OnlyOneOption.Option2;

因为就整数而言,该操作看起来非常好。正如您所指出的,您可以做的是提供FlagsAttribute - 这对开发人员来说已经是一个很好的提示。

you cannot overload operatorsenum 上,您必须求助于运行时检查。

运行时检查

您可以做的是,在您需要枚举的任何时候,检查是否完全相等,并在使用值组合时抛出异常。最快最干净的方法是使用 switch:

// Use the bit pattern to guarantee that e.g. OptionX | OptionY
// never accidentally ends up as another valid option.
enum OnlyOneOption { Option1 = 0x001, Option2 = 0x002, Option3 = 0x004, ... };

switch(option) {
  case OnlyOneOption.Option1: 
    // Only Option1 selected - handle it.
    break;

  case OnlyOneOption.Option2: 
    // Only Option2 selected - handle it.
    break;

  default:
    throw new InvalidOperationException("You cannot combine OnlyOneOption values.");
}

非枚举解决方案

如果您不坚持使用 enum,您可以求助于经典的(Java-ish)静态模式:

class OnlyOneOption
{
    // Constructor is private so users cannot create their own instances.
    private OnlyOneOption() {} 

    public static OnlyOneOption OptionA = new OnlyOneOption();
    public static OnlyOneOption OptionB = new OnlyOneOption();
    public static OnlyOneOption OptionC = new OnlyOneOption();
}

这里 OnlyOneOption option = OnlyOneOption.OptionA | OnlyOneOption.OptionB; 将失败并出现错误 CS0019:“Operator '|'不能应用于“OnlyOneOption”和“OnlyOneOption”类型的操作数”。

缺点是您无法编写 switch 语句,因为它们实际上需要编译时常量转换为 int(我尝试提供一个 static public implicit operator int 返回一个 readonly 字段,但即使这样还不够——“需要一个常量值”)。

关于c# - 如何防止枚举值的按位或组合?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38522488/

相关文章:

c# - 带负号 (-) 和点号 (.) 的数字键盘

bash - `-s --` 标志对 npm 有什么作用?

prolog - current_prolog_flag double_quotes DCG(代码或字符)?

c# - 当在 C# 中调用任何其他方法时,如何自动重置 bool 值?

java - Java 函数式接口(interface)的单例作为枚举

java - Spring中是否可以使用枚举来实现策略模式

c# - 根据标签运行某些 .NET Core 健康检查

c# - 推荐游戏的 Sprite 大小(XNA)?

c# - WPF MVVM 模式中的关注点分离

c# - 具有数据注释的枚举类型的 Json.NET 自定义序列化