简体   繁体   English

从逗号分隔的列表或整数中解析枚举标志

[英]Parsing enum flags from comma-separated list or integer

I have an XML that contains several flags, some of them are unsigned 32-bit integers and others are unsigned 64-bit integers. 我有一个包含几个标志的XML,其中一些是无符号的32位整数,另一些是无符号的64位整数。 Some of them are written in a comma-separated list and others are in hex style. 其中一些是用逗号分隔的列表编写的,另一些是十六进制的。

See this example: 看这个例子:

<Color>Blue,Red</Color>
<Color>0xC</Color>

As I don't want to write a method to parse each enum, I decided to use a generic method. 因为我不想编写解析每个枚举的方法,所以我决定使用泛型方法。 But Visual Studio won't let me build the solution. 但Visual Studio不会让我构建解决方案。 Here's my method: 这是我的方法:

public static T ParseFlags<T>(string value) where T : struct
{
    T result = (T)((object)0);
    string[] array;
    // Remove white spaces and delimit string if it is comma-separated
    if (ParseDelimitedString(value, ',', out array))
    {
        for (int i = 0; i < array.Length; i++)
        {
            T flag = (T)((object)0);
            // Check if value is member of enumeration
            if (Enum.TryParse<T>(array[i], out flag))
            {
                result |= (T)((object)flag);
            }
        }
    }
    else
    {
        switch (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))))
        {
            // Remove hex characters and parse node's inner text
            case TypeCode.UInt32:
                result = (T)((object)ParseUint(value));
                break;
            case TypeCode.UInt64:
                result = (T)((object)ParseUlong(value));
                break;
        }
    }
    return result;
}

The error message I get is: 我得到的错误信息是:

Error 1 Operator '|=' cannot be applied to operands of type 'T' and 'T' 错误1运算符'| ='不能应用于'T'和'T'类型的操作数

Is there a way to do this? 有没有办法做到这一点?

You are doing a lot of work that can be done for you. 你正在做很多可以为你做的工作。 For example, if your enum is declared with the FlagsAttribute then Enum.Parse will parse comma separated values for you. 例如,如果使用FlagsAttribute声明enum ,则Enum.Parse将为您解析逗号分隔值。

public static T ParseFlags<T>(string value) where T : struct
{
    T result;
    ulong temp;
    if (Enum.TryParse(value, out result))
    {
        return result;
    }

    string hexNum = value.StartsWith("0x") ? value.Substring(2) : value;
    if (ulong.TryParse(hexNum, NumberStyles.HexNumber, null, out temp))
    {
        return (T)Enum.ToObject(typeof(T), temp);
    }

    throw new ArgumentException("value could not be parsed");
}

I tested this with various Flags enum types with short , int , and ulong backing values. 我使用具有shortintulong支持值的各种Flags枚举类型对此进行了测试。

If you know what type of enum you're parsing: 如果你知道你正在解析什么类型的枚举:

    [Fact]
    public void when_parsing_options_then_can_combine_flags()
    {
        var values = "Singleline | Compiled";

        var options = values.Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries)
            .Select(value => (RegexOptions)Enum.Parse(typeof(RegexOptions), value))
            .Aggregate(RegexOptions.None, (current, value) => current |= value);

        Assert.Equal(RegexOptions.Singleline | RegexOptions.Compiled, options);
    }

Try this: 尝试这个:

public static T ParseFlags<T>(string value) where T : struct
{
    long result = 0L;
    string[] array;
    // Remove white spaces and delimit string if it is comma-separated
    if (ParseDelimitedString(value, ',', out array))
    {
        for (int i = 0; i < array.Length; i++)
        {
            T flag = default(T);
            // Check if value is member of enumeration
            if (Enum.TryParse<T>(array[i], out flag))
            {
                result |= (long)flag;
            }
        }
    }
    else
    {
        switch (Type.GetTypeCode(Enum.GetUnderlyingType(typeof(T))))
        {
            // Remove hex characters and parse node's inner text
            case TypeCode.UInt32:
                result = ParseUint(value);
                break;
            case TypeCode.UInt64:
                result = ParseUlong(value);
                break;
        }
    }
    return (T)((object)result);
}

Hope it helps. 希望能帮助到你。

"|=" usage in that snippet makes me think you meant to use the Enum as bitset not just any old Enum. “| =”该片段中的用法让我觉得你的意思是将Enum用作bitset而不仅仅是任何旧的Enum。 If this is true, you should make a small change - declare the local "result" as int and adjust the casts appropriately, your return statement should then be "return (T)(object)result;". 如果这是真的,你应该做一个小改动 - 将本地“result”声明为int并适当调整转换,你的return语句应该是“return(T)(object)result;”。 That line in question with "|" 与“|”有关的那一行 would look like: "result |= (int)(object)flag;". 看起来像:“result | =(int)(object)flag;”。 Perhaps, there is a better answer but, note that enums are integers and your scenario of bitset are covered well enough with this solution unless there are situations I missed or you did not state. 也许,有一个更好的答案,但是,请注意, 枚举是整数,并且您的bitset的场景已经足够覆盖此解决方案,除非有我错过的情况或您没有陈述。

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

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