Есть ли более простой способ разобрать int для общего перечисления Flags? - PullRequest
0 голосов
/ 18 октября 2019

У меня есть универсальная функция для анализа объекта в универсальный Enum.

Тем не менее, я сталкиваюсь с проблемой при попытке безопасно разобрать int в Enum [Flags].

Непосредственное использование Enum.ToObject () работает для анализа допустимых комбинаций, но просто возвращает исходное значение, если комбинации флагов нет.

Кроме того, когда нет явного члена перечисления для комбинации флагов, Enum.ToName () и Enum.IsDefined () не возвращают полезные значения.

Например:

[Flags]
public enum Color
{
   None = 0,
   Red = 1,
   Green = 2,
   Blue = 4,
}

// Returns 20
Enum.ToObject(typeof(Color), 20)

// Returns ""
Enum.ToName(typeof(Color), 3)

// Returns false
Enum.IsDefined(typeof(Color), 3)

Я написал функцию, которая, на мой взгляд, работает технически, но, похоже, должен быть лучший способ сделать это.

Моя функция:

public static T ParseEnumerator<T>(object parseVal, T defaultVal) where T : struct, IConvertible
{
    Type ttype = typeof(T);

    if (!ttype.IsEnum)
    {
        throw new ArgumentException("T must be an enumerated type");
    }

    bool isFlag = ttype.GetCustomAttribute(typeof(FlagsAttribute)) != null;

    try
    {
        if (parseVal == null)
        {
            return defaultVal;
        }
        else if (parseVal is T)
        {
            return (T)parseVal;
        }
        else if (parseVal is string)
        {
            return (T)Enum.Parse(ttype, parseVal.ToString(), true);
        }
//**************** The section at issue **********************************/
        else if (isFlag && parseVal is int)
        {
            List<string> flagsList = new List<string>();
            int maxVal = 0;

            //Loop through each bit flag
            foreach (var val in Enum.GetValues(ttype))
            {
                if (CountBits((int)val) == 1)
                {
                    if ((int)val > maxVal)
                        maxVal = (int)val;

                    // If the current bit is set, add the flag to the result
                    if (((int)parseVal & (int)val) == (int)val)
                    {
                        string enumName = Enum.GetName(ttype, val);
                        if (!string.IsNullOrEmpty(enumName))
                            flagsList.Add(enumName);
                    } 
                }
            }

            // Is the value being parsed over the highest bitwise value?
            if ((int)parseVal >= (maxVal << 1))
                return defaultVal;
            else
                return (T)Enum.Parse(ttype, string.Join(",", flagsList));
        }
//************************************************************************/
        else
        {
            string val = Enum.GetName(ttype, parseVal);
            if (!string.IsNullOrEmpty(val))
                return (T)Enum.ToObject(ttype, parseVal);
            else
                return defaultVal;
        }
    }
    catch
    {
        return defaultVal;
    }
}

Есть ли что-то, что я пропускаю? Или есть другой способ безопасно проанализировать эти значения?

Любая помощь приветствуется, спасибо!

-MM

1 Ответ

1 голос
/ 18 октября 2019

Поскольку ваша универсальная функция должна знать тип Enum для начала, вы можете просто отказаться от функции и использовать вместо нее базовое приведение.

using System;

namespace SO_58455415_enum_parsing {

    [Flags]
    public enum CheeseCharacteristics {
        Yellow = 1,
        Mouldy = 2,
        Soft = 4,
        Holed = 8
    }

    public static class Program {
        static void Main(string[] args) {
            CheeseCharacteristics cc = (CheeseCharacteristics)12;
            Console.WriteLine(cc);
        }
    }
}

Если все, что вы хотите знать, это наличие значенияэто может быть создано с использованием флагов перечисления ... это довольно просто, при условии, что мы можем предположить, что каждый флаг является "последовательным" (например, между флагами нет пробелов). Все числа от 1 до суммы всех значений флагов могут быть получены с помощью некоторой комбинации флагов. Вы можете просто сложить значения флагов вместе и сравнить их со значением вашего вопроса.

public static bool IsValidFlags<T>(int checkValue) where T:Enum {
    int maxFlagValue = ((int[])Enum.GetValues(typeof(T))).Sum();

    return (0 < checkValue) && (checkValue <= maxFlagValue);
}

Для дальнейшего использования вы можете ограничить свой общий параметр перечислением:

void fx<T> () where T:Enum { }
...