[c#] Enum 값을 TryParse하는 방법은 무엇입니까?

가능한 값에 대해 주어진 값 (문자열로 전달됨)의 유효성을 검사 할 수있는 함수를 작성하고 싶습니다 enum. 일치하는 경우 열거 형 인스턴스를 반환해야합니다. 그렇지 않으면 기본값을 반환해야합니다.

함수는 내부적으로 try/를 사용하지 않을 수 있습니다 . 이는 유효하지 않은 인수가 주어지면 예외를 발생시키는 catchusing을 제외합니다 Enum.Parse.

이것을 TryParse구현하기 위해 함수 라인을 따라 무언가를 사용하고 싶습니다 .

public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
   object enumValue;
   if (!TryParse (typeof (TEnum), strEnumValue, out enumValue))
   {
       return defaultValue;
   }
   return (TEnum) enumValue;
}



답변

다른 사람들이 말했듯이 자신 만의 TryParse. Simon Mourier는 모든 것을 처리하는 완전한 구현을 제공합니다.

비트 필드 열거 형 (즉 플래그)을 사용하는 경우 "MyEnum.Val1|MyEnum.Val2"두 열거 형 값의 조합 인 문자열도 처리해야 합니다. Enum.IsDefined이 문자열로 호출 Enum.Parse하면 올바르게 처리 하더라도 false를 반환 합니다.

최신 정보

주석에서 Lisa와 Christian이 언급했듯이 Enum.TryParse이제 .NET4 이상에서 C #을 사용할 수 있습니다.

MSDN 문서


답변

Enum.IsDefined는 작업을 완료합니다. TryParse만큼 효율적이지 않을 수 있지만 예외 처리없이 작동합니다.

public static TEnum ToEnum<TEnum>(this string strEnumValue, TEnum defaultValue)
{
    if (!Enum.IsDefined(typeof(TEnum), strEnumValue))
        return defaultValue;

    return (TEnum)Enum.Parse(typeof(TEnum), strEnumValue);
}

주목할만한 점 TryParse은 .NET 4.0에 메서드가 추가되었습니다.


답변

다음은 EnumTryParse. 다른 일반적인 구현과 달리 Flags속성으로 표시된 열거 형도 지원 합니다.

    /// <summary>
    /// Converts the string representation of an enum to its Enum equivalent value. A return value indicates whether the operation succeeded.
    /// This method does not rely on Enum.Parse and therefore will never raise any first or second chance exception.
    /// </summary>
    /// <param name="type">The enum target type. May not be null.</param>
    /// <param name="input">The input text. May be null.</param>
    /// <param name="value">When this method returns, contains Enum equivalent value to the enum contained in input, if the conversion succeeded.</param>
    /// <returns>
    /// true if s was converted successfully; otherwise, false.
    /// </returns>
    public static bool EnumTryParse(Type type, string input, out object value)
    {
        if (type == null)
            throw new ArgumentNullException("type");

        if (!type.IsEnum)
            throw new ArgumentException(null, "type");

        if (input == null)
        {
            value = Activator.CreateInstance(type);
            return false;
        }

        input = input.Trim();
        if (input.Length == 0)
        {
            value = Activator.CreateInstance(type);
            return false;
        }

        string[] names = Enum.GetNames(type);
        if (names.Length == 0)
        {
            value = Activator.CreateInstance(type);
            return false;
        }

        Type underlyingType = Enum.GetUnderlyingType(type);
        Array values = Enum.GetValues(type);
        // some enums like System.CodeDom.MemberAttributes *are* flags but are not declared with Flags...
        if ((!type.IsDefined(typeof(FlagsAttribute), true)) && (input.IndexOfAny(_enumSeperators) < 0))
            return EnumToObject(type, underlyingType, names, values, input, out value);

        // multi value enum
        string[] tokens = input.Split(_enumSeperators, StringSplitOptions.RemoveEmptyEntries);
        if (tokens.Length == 0)
        {
            value = Activator.CreateInstance(type);
            return false;
        }

        ulong ul = 0;
        foreach (string tok in tokens)
        {
            string token = tok.Trim(); // NOTE: we don't consider empty tokens as errors
            if (token.Length == 0)
                continue;

            object tokenValue;
            if (!EnumToObject(type, underlyingType, names, values, token, out tokenValue))
            {
                value = Activator.CreateInstance(type);
                return false;
            }

            ulong tokenUl;
            switch (Convert.GetTypeCode(tokenValue))
            {
                case TypeCode.Int16:
                case TypeCode.Int32:
                case TypeCode.Int64:
                case TypeCode.SByte:
                    tokenUl = (ulong)Convert.ToInt64(tokenValue, CultureInfo.InvariantCulture);
                    break;

                //case TypeCode.Byte:
                //case TypeCode.UInt16:
                //case TypeCode.UInt32:
                //case TypeCode.UInt64:
                default:
                    tokenUl = Convert.ToUInt64(tokenValue, CultureInfo.InvariantCulture);
                    break;
            }

            ul |= tokenUl;
        }
        value = Enum.ToObject(type, ul);
        return true;
    }

    private static char[] _enumSeperators = new char[] { ',', ';', '+', '|', ' ' };

    private static object EnumToObject(Type underlyingType, string input)
    {
        if (underlyingType == typeof(int))
        {
            int s;
            if (int.TryParse(input, out s))
                return s;
        }

        if (underlyingType == typeof(uint))
        {
            uint s;
            if (uint.TryParse(input, out s))
                return s;
        }

        if (underlyingType == typeof(ulong))
        {
            ulong s;
            if (ulong.TryParse(input, out s))
                return s;
        }

        if (underlyingType == typeof(long))
        {
            long s;
            if (long.TryParse(input, out s))
                return s;
        }

        if (underlyingType == typeof(short))
        {
            short s;
            if (short.TryParse(input, out s))
                return s;
        }

        if (underlyingType == typeof(ushort))
        {
            ushort s;
            if (ushort.TryParse(input, out s))
                return s;
        }

        if (underlyingType == typeof(byte))
        {
            byte s;
            if (byte.TryParse(input, out s))
                return s;
        }

        if (underlyingType == typeof(sbyte))
        {
            sbyte s;
            if (sbyte.TryParse(input, out s))
                return s;
        }

        return null;
    }

    private static bool EnumToObject(Type type, Type underlyingType, string[] names, Array values, string input, out object value)
    {
        for (int i = 0; i < names.Length; i++)
        {
            if (string.Compare(names[i], input, StringComparison.OrdinalIgnoreCase) == 0)
            {
                value = values.GetValue(i);
                return true;
            }
        }

        if ((char.IsDigit(input[0]) || (input[0] == '-')) || (input[0] == '+'))
        {
            object obj = EnumToObject(underlyingType, input);
            if (obj == null)
            {
                value = Activator.CreateInstance(type);
                return false;
            }
            value = obj;
            return true;
        }

        value = Activator.CreateInstance(type);
        return false;
    }


답변

결국 이것을 구현해야합니다 Enum.GetNames.

public bool TryParseEnum<T>(string str, bool caseSensitive, out T value) where T : struct {
    // Can't make this a type constraint...
    if (!typeof(T).IsEnum) {
        throw new ArgumentException("Type parameter must be an enum");
    }
    var names = Enum.GetNames(typeof(T));
    value = (Enum.GetValues(typeof(T)) as T[])[0];  // For want of a better default
    foreach (var name in names) {
        if (String.Equals(name, str, caseSensitive ? StringComparison.Ordinal : StringComparison.OrdinalIgnoreCase)) {
            value = (T)Enum.Parse(typeof(T), name);
            return true;
        }
    }
    return false;
}

추가 참고 사항 :

  • Enum.TryParse.NET 4에 포함되어 있습니다 . 여기를 참조하십시오. http://msdn.microsoft.com/library/dd991876(VS.100).aspx
  • 또 다른 접근 방식은 Enum.Parse실패 할 때 throw되는 예외를 포착하여 직접 래핑하는 것 입니다. 일치하는 항목이 발견되면 더 빠를 수 있지만 그렇지 않은 경우 속도가 느려질 수 있습니다. 처리중인 데이터에 따라 이것은 순 개선 일 수도 있고 아닐 수도 있습니다.

편집 : 필요한 정보를 캐시하는 더 나은 구현을 보았습니다. http://damieng.com/blog/2010/10/17/enums-better-syntax-improved-performance-and-tryparse-in-net- 3-5


답변

.NET 4.5 기반

아래 샘플 코드

using System;

enum Importance
{
    None,
    Low,
    Medium,
    Critical
}

class Program
{
    static void Main()
    {
    // The input value.
    string value = "Medium";

    // An unitialized variable.
    Importance importance;

    // Call Enum.TryParse method.
    if (Enum.TryParse(value, out importance))
    {
        // We now have an enum type.
        Console.WriteLine(importance == Importance.Medium);
    }
    }
}

참조 : http://www.dotnetperls.com/enum-parse


답변

UnconstrainedMelody 에서 사용할 수있는 최적화 된 구현이 있습니다 . 실제로는 이름 목록을 캐싱하는 것이지만 멋지고 강력하게 형식화되고 일반적으로 제한되는 방식으로 수행됩니다. 🙂


답변

enum EnumStatus
{
    NAO_INFORMADO = 0,
    ENCONTRADO = 1,
    BLOQUEADA_PELO_ENTREGADOR = 2,
    DISPOSITIVO_DESABILITADO = 3,
    ERRO_INTERNO = 4,
    AGARDANDO = 5
}

if (Enum.TryParse<EnumStatus>(item.status, out status)) {

}