我知道你可以FlagsAttribute用来指示编译器使用位域进行枚举.
有没有办法指定枚举值不能与按位OR组合?
例:
enum OnlyOneOption
{
Option1,
Option2,
...
}
Run Code Online (Sandbox Code Playgroud)
在这个例子中,没有什么能阻止开发人员写作OnlyOneOption.Option1 | OnlyOneOption.Option2.如果可能的话,我想在编译时禁止它.
Com*_*hip 27
最近,Eric Lippert(他在微软期间从事过C#编译器工作的人之一)发表了关于他对C#的十大遗憾的博客,其中四位是
在C#中,枚举只是基础整数类型的瘦类型系统包装器.枚举上的所有操作都被指定为实际上对整数的操作,枚举值的名称类似于命名常量.
所以原则上,你不能让编译器窒息
OnlyOneOption option = OnlyOneOption.Option1 | OnlyOneOption.Option2;
Run Code Online (Sandbox Code Playgroud)
因为在整数方面,这种操作看起来非常好.正如您所指出的,您可以做的是不提供FlagsAttribute- 这对开发人员来说已经是一个很好的暗示.
既然你不能在enums 上重载运算符,你必须求助于运行时检查.
您可以做的是,只要您需要枚举,检查确切的相等性以及throw使用值组合时的异常.最快最干净的方法是使用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.");
}
Run Code Online (Sandbox Code Playgroud)
如果你不坚持使用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();
}
Run Code Online (Sandbox Code Playgroud)
这OnlyOneOption option = OnlyOneOption.OptionA | OnlyOneOption.OptionB;将失败,错误CS0019:" 运算符'|' 不能应用于'OnlyOneOption'和'OnlyOneOption'类型的操作数.
缺点是您失去了编写switch语句的能力,因为它们实际上需要编译时常量转换int(我尝试提供一个static public implicit operator int返回readonly字段,但即使这还不够 - "预期值为常量值").
不,你不能阻止这一点.不指定[Flags]属性不会禁止以下用户:
enum Option
{
One = 1,
Two,
Three
}
var myOption = Option.One | Option.Two;
Run Code Online (Sandbox Code Playgroud)
此外,完全合法的东西如下:
var myOption = 0; //language quirk IMO, 0 being implicitly convertible to any enumeration type.
Run Code Online (Sandbox Code Playgroud)
要么
var myOption = (Option)33;
Run Code Online (Sandbox Code Playgroud)
这是一个问题吗?不,不是真的; 如果您的逻辑只考虑选项One,Two或者Three只是强制执行它:
public Foo Bar(Option myOption)
{
switch (myOption)
{
case Option.One: ...
case Option.Two: ...
case Option.Three: ...
default: //Not a valid option, act in consequence
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,如果您有(可疑)代码根据枚举的基础值决定:
if (myOption < Option.Three) { //expecting myOption to be either One or Two...
Run Code Online (Sandbox Code Playgroud)
那么你肯定没有使用合适的工具来完成工作; myOption = 0;或者myOption = (Option)-999会有问题.
| 归档时间: |
|
| 查看次数: |
1572 次 |
| 最近记录: |