打印标志枚举作为单独的标志

Bri*_*ian 9 c# enums flags

我有一个像这样定义的标志枚举:

[Flags]
public enum MyEnum
{
    None =     0x00,
    Choice1 =  0x01,
    Choice2 =  0x02,
    Choice3 =  0x04,
    Default =  Choice1 | Choice2,
    All =      Default | Choice3
}
Run Code Online (Sandbox Code Playgroud)

我想要一种方法来打印出包含哪些标志MyEnum.Default.在这种情况下,我希望输出类似于"Choice1,Choice2".

简单打印的问题MyEnum.Default.ToString()是当我想要"Choice1,Choice2"时输出将是"默认".

这是一个选项,但如果我使用它,我每次更改枚举时都必须更新打印.

((StudyData.Choice1 & StudyData.Default) == StudyData.Choice1 ? StudyData.Choice1.ToString() : "") + ", " +
((StudyData.Choice2 & StudyData.Default) == StudyData.Choice2 ? StudyData.Choice2.ToString() : "") + ", " +
((StudyData.Choice3 & StudyData.Default) == StudyData.Choice3 ? StudyData.Choice3.ToString() : "")
Run Code Online (Sandbox Code Playgroud)

有没有人有更清洁的方式这样做?理想情况下,我想要一种打印出包含的标志的方法,MyEnum.Default而不必在每次添加新标志或更改默认值时更改打印代码.

谢谢!

Jef*_*ado 15

使用我在这里写的相关问题的扩展方法,这应该很简单:

var value = MyEnum.Default;
var str = String.Join(", ", value.GetIndividualFlags());
// "Choice1, Choice2"
Run Code Online (Sandbox Code Playgroud)

这是扩展方法:

static class EnumExtensions
{
    public static IEnumerable<Enum> GetFlags(this Enum value)
    {
        return GetFlags(value, Enum.GetValues(value.GetType()).Cast<Enum>().ToArray());
    }

    public static IEnumerable<Enum> GetIndividualFlags(this Enum value)
    {
        return GetFlags(value, GetFlagValues(value.GetType()).ToArray());
    }

    private static IEnumerable<Enum> GetFlags(Enum value, Enum[] values)
    {
        ulong bits = Convert.ToUInt64(value);
        List<Enum> results = new List<Enum>();
        for (int i = values.Length - 1; i >= 0; i--)
        {
            ulong mask = Convert.ToUInt64(values[i]);
            if (i == 0 && mask == 0L)
                break;
            if ((bits & mask) == mask)
            {
                results.Add(values[i]);
                bits -= mask;
            }
        }
        if (bits != 0L)
            return Enumerable.Empty<Enum>();
        if (Convert.ToUInt64(value) != 0L)
            return results.Reverse<Enum>();
        if (bits == Convert.ToUInt64(value) && values.Length > 0 && Convert.ToUInt64(values[0]) == 0L)
            return values.Take(1);
        return Enumerable.Empty<Enum>();
    }

    private static IEnumerable<Enum> GetFlagValues(Type enumType)
    {
        ulong flag = 0x1;
        foreach (var value in Enum.GetValues(enumType).Cast<Enum>())
        {
            ulong bits = Convert.ToUInt64(value);
            if (bits == 0L)
                //yield return value;
                continue; // skip the zero value
            while (flag < bits) flag <<= 1;
            if (flag == bits)
                yield return value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 请注意,如果您的枚举具有负值(例如使用 Visual Studio 可扩展性框架 Microsoft.VisualStudio.Shell.Interop._VSRDTFLAGS),那么在此处使用 ulong 和 ToUInt64 将导致问题。如果用 long 和 ToInt64 替换,则它将处理具有负值的枚举。 (2认同)

Pet*_*e M 6

FlagsAttribute装饰枚举。它几乎可以完全满足您的要求:

[Flags]
public enum FooNum
{
    foo = 0,
    bar = 1,
    lulz = 2,
    borkbork = 4
}

FooNum f = FooNum.bar | FooNum.borkbork;

Debug.WriteLine(f.ToString());
Run Code Online (Sandbox Code Playgroud)

应该给你:

酒吧,博克博克

  • 哦,我知道你现在在做什么。即使您使用`yourEnum = yourEnum.Choice1 |手动构造`Default`,此问题仍然存在。yourEnum.Choice2`,当您将其推出一个字符串时,仍将获得`yourEnum.Default`。您在枚举本身上需要Default和All定义有多严重?您将不得不像之前已经发现的那样,将钻头走路并分别拉出它们。无论如何,都会有些混乱。另一种选择是将默认值存储为自己的FooNum。但这以自己的方式是混乱的... (2认同)