繁体   English   中英

为什么在枚举中声明位域的组合与在枚举之外声明它会产生不同的结果?

[英]Why does declaring a combination of bit fields inside an enum produce a different result than declaring it outside of the enum?

在这里,我有一个由位字段指示的主题列表,其中包含底部的可选主题的“可选”字段。

[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"

现在,如果我要在枚举之外声明相同的 Optional 字段并记录它:

// 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"

它按预期工作。

所以我的问题是,当我将组合位字段放在枚举中而不是将其放在枚举之外时,为什么我会收到不同的 output?

您可以通过以下方式编写枚举声明,并给出相同的结果:

[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);
 }

或者您可以编写自己的方法将您的枚举转换为字符串,也许使用description 属性来获取Optional字段的另一个值

您没有区分枚举值和变量,但它们非常不同。


枚举滥用

顺便说一句,我认为您通过尝试将有关这些枚举值的一些额外元数据(即它们是否是可选的)潜入组合的Optional字段中来滥用枚举的目的。

我怀疑对您来说最好的解决方案是完全放弃使用枚举,因为枚举值不应该有更多的元数据围绕它们。

我仍然回答了这个问题,因为我对枚举滥用的怀疑完全是基于一个名字和我对你的含义的解释。 由您决定是否尝试在枚举中隐藏一些元数据,或者我是否误解了您的意图。


枚举值

[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是一个变量而不是枚举值。 这里只有两个枚举值, ArtAgriculture

在这种情况下,您没有将Optional定义为枚举值,因此编译器无法使用或引用不存在的枚举值。

因此,它依赖于找出枚举值的哪个组合将导致(组合的) optional值,并且它意识到通过组合Subject.ArtSubject.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 )时,这是不可避免的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM