在这里,我有一个由位字段表示的主题列表,底部有一个包含可选主题的 "可选 "字段。
[Flags]
enum Subjects
{
Art = 0b_0000_0001,
Agriculture = 0b_0000_0010,
English = 0b_0000_0100,
Geography = 0b_0000_1000,
Maths = 0b_0001_0000,
Science = 0b_0010_0000,
Optional = Art | Agriculture,
}
当我将可选科目打印到控制台时,我得到了一个意外的结果。
Console.WriteLine(Subjects.Optional); // returns "Optional", I expected "Art, Agriculture"
现在,如果我在枚举外声明同样的可选字段并记录下来,
// NOTE: I had to comment out the "Optional" field, otherwise it would return Optional once again
var optional = Subjects.Art | Subjects.Agriculture;
Console.WriteLine(optional); // returns "Art, Agriculture" not "Optional"
它就能正常工作
所以我的问题是,为什么我将组合位字段放在enum中与放在enum之外时,收到的输出不同?
你并没有区分枚举值和变量,但这些是非常不同的。
旁白,我认为你在滥用枚举的目的,试图将一些关于这些枚举值的额外元数据(即它们是否是可选的)偷偷放到组成的 Optional
字段。
我怀疑对你来说,最好的解决办法是完全放弃使用枚举,因为枚举值不应该有更多的元田围绕着它们。
我仍然回答了这个问题,因为我对enum滥用的怀疑完全是基于一个名字和我对它对你的意义的解释。是你想在enum中偷偷加入一些元数据,还是我误解了你的意图,由你来决定。
[Flags]
enum Subjects
{
Art = 0b_0000_0001,
Agriculture = 0b_0000_0010,
Optional = Art | Agriculture,
}
当你把组成的值包含在枚举中时,你把它定义为一个有效的枚举值。你实际上是在告诉编译器 Subjects.Optional
是一个有效的(因此是有意义的)枚举值,这意味着这个可以而且应该被使用。
这就导致编译器使用 Subjects.Optional
值(和它的字符串表示法,即 "Optional"
),因为你告诉编译器它对你是有意义的。
[Flags]
enum Subjects
{
Art = 0b_0000_0001,
Agriculture = 0b_0000_0010
}
var optional = Subjects.Art | Subjects.Agriculture;
重要的是要认识到 optional
是一个 可变的 而不是一个枚举值。这里只有两个枚举值。Art
和 Agriculture
.
在这种情况下,您没有定义 Optional
是一个枚举值,因此编译器不能使用或引用一个不存在的枚举值。
因此,它又回到了找出哪种枚举值的组合会导致(组合)的 optional
价值,并且它意识到,通过将 Subject.Art
和 Subject.Agriculture
的值,你会得到由 optional
这就是为什么它返回一个逗号分隔的字符串 Art, Agriculture
.
如果你想得到逗号分隔的字符串,同时又要保留枚举本身的组成值,你将不得不自己生成逗号分隔的字符串。比如说
public string AsCommaSeparatedString(Subjects myEnum)
{
var possibleSubjects = new List<Subjects>() { Subjects.Art, Subjects.Agriculture };
var subjects = possibleSubjects.Where(possibleSubject => myEnum.HasFlag(possibleSubject));
return String.Join(",", names);
}
你必须列出所有你想包含的枚举值(所以其他的值比如 Optional
将被忽略),但当你特别想排除一些值时,这是不可避免的(如 Optional
)不被提及。
你可以用下面的方式写你的枚举声明,得到同样的结果。
[Flags]
enum Subjects
{
Art = 0b_0000_0001,
Agriculture = 0b_0000_0010,
English = 0b_0000_0100,
Geography = 0b_0000_1000,
Maths = 0b_0001_0000,
Science = 0b_0010_0000,
Optional = 0b_0000_0011
}
编译器怎么知道 Optional
是一个组成的字段?当一个字段存在时,它将被选择在 ToString()
方法。如果您想避免这种情况,您可以删除 Optional
字段并添加一个扩展方法。
public bool IsOptional(this Subjects subjects)
{
return subjects.HasFlag(Subjects.Art) && subjects.HasFlag(Subjects.Agriculture);
}
或者你也可以写你自己的方法 把你的枚举转换为字符串,也许可以使用 描述属性 来获得另一个值 Optional
领域