Как попробоватьParse для значения Enum?

Я хочу написать функцию, которая может проверять заданное значение (передается в виде строки) по возможным значениямenum, В случае совпадения он должен вернуть экземпляр enum; в противном случае он должен вернуть значение по умолчанию.

Функция не может использоваться внутриtry/catch, что исключает использование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;
}
 Domenic04 июл. 2009 г., 18:46
Я не понимаю этого вопроса; Вы говорите: «Я хочу решить эту проблему, но я не хочу использовать ни один из методов, которые дадут мне решение». В чем смысл
 akmad24 сент. 2009 г., 17:09
@ Amby, стоимость простого входа в блок try / catch ничтожна. Стоимость БРОСЕНИЯ не исключение, но тогда это должно быть исключительным, нет? Кроме того, не говорите «мы никогда не узнаем» ... профилируйте код и узнайте. Не тратьте свое время на размышления, если что-то идет медленно, НАЙДИТЕ!
 Manish Basantani04 июл. 2009 г., 19:38
@ Domenic: я просто ищу лучшее решение, чем то, что я уже знаю. Пойдете ли вы когда-нибудь на железнодорожный запрос, чтобы узнать маршрут или поезд, который вы уже знаете :).
 Thorarin04 июл. 2009 г., 19:24
Стоимость обработки исключений не так уж и плоха. Черт, внутренние реализации всего этого преобразования перечисления полны обработки исключений. Мне действительно не нравится, когда исключения генерируются и отлавливаются во время обычной логики приложения. Иногда бывает полезно разбить все исключения, которые выдают (даже когда они пойманы). Создание исключений повсюду сделает это намного более раздражающим для использования:)
 SolutionYogi04 июл. 2009 г., 19:09
Каково твое отвращение, чтобы попробовать / поймать решение? Если вы пытаетесь избежать Exception, потому что они «дорогостоящие», пожалуйста, дайте себе перерыв. В 99% случаев исключение стоимости выбрасывания / улова незначительно по сравнению с вашим основным кодом.

Ответы на вопрос(14)

которую вы можете использовать в UnconstrainedMelody. По сути, он просто кэширует список имен, но делает это хорошо, строго типизировано, с общими ограничениями:)

Решение Вопроса

TryParse. Саймон Мурье обеспечивает полную реализацию, которая заботится обо всем.

Если вы используете перечисления битовых полей (т. Е. Флаги), вы также должны обрабатывать строку наподобие"MyEnum.Val1|MyEnum.Val2", который является комбинацией двух значений enum. Если вы просто позвонитеEnum.IsDefined с этой строкой, он вернет false, хотяEnum.Parse справляется с этим правильно.

Обновит

Как упоминали Лиза и Кристиан в комментариях,Enum.TryParse теперь доступен для C # в .NET4 и выше.

MSDN Docs

 Christian19 сент. 2013 г., 11:36
Как упомянуто ниже, но на самом деле не видно: с .Net 4 Enum.TryParse доступен и работает без дополнительного кодирования. Дополнительная информация доступна на MSDN: Msdn.microsoft.com / библиотека / VStudio / dd991317% 28В =% против 100 29.aspx
 Lisa29 нояб. 2011 г., 07:03
Возможно, наименее привлекательный, но я согласен, что это определенно лучше, пока ваш код не будет перенесен в .NET 4.

но я не уверен насчет трипса.

 Manish Basantani04 июл. 2009 г., 18:38
Я знаю о методе Enum.Parse (typeof (TEnum), strEnumValue). Выдает ArgumentException, если strEnumValue недопустимо. Ищете TryParse ........

Вот пользовательская реализация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;
    }
 Christian19 сент. 2013 г., 11:34
Как упомянуто ниже, но на самом деле не видно: с .Net 4 Enum.TryParse доступен и работает без дополнительного кодирования. Дополнительная информация доступна на MSDN: Msdn.microsoft.com / библиотека / VStudio / dd991317% 28В =% против 100 29.aspx
 Pierre Arnaud13 сент. 2011 г., 15:31
Вы предоставили лучшую реализацию, и я использовал ее в своих целях; Однако мне интересно, почему вы используетеActivator.CreateInstance(type) для создания значения перечисления по умолчанию, а неEnum.ToObject(type, 0). Просто дело вкуса?
 Simon Mourier13 сент. 2011 г., 15:46
@ Pierre - Хммм ... нет, в то время это казалось более естественным :-) Может быть, Enum.ToObject работает быстрее, поскольку он использует внутренний вызов InternalBoxEnum? Я никогда не проверял это ...

вы должны реализовать это вокруг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 перехватывает исключение, которое выдается при сбое. Это может быть быстрее, когда найдено совпадение, но, скорее всего, будет медленнее, если нет. В зависимости от данных, которые вы обрабатываете, это может или не может быть чистым улучшением.

EDIT: только что видел лучшую реализацию этого, которая кэширует необходимую информацию:http: //damieng.com/blog/2010/10/17/enums-better-syntax-improved-performance-and-tryparse-in-net-3-

 Daniel Ballinger24 нояб. 2009 г., 22:51
Я собирался предложить использовать default (T), чтобы установить значение по умолчанию. Оказывается, это не будет работать для всех перечислений. Например. Если базовый тип для перечисления был int default (T) всегда будет возвращать 0, что может быть или не быть допустимым для перечисления.
 Uwe Keim02 июл. 2013 г., 11:16
Реализация в блоге Дамиенга делаетн поддерживает перечисления сFlags атрибут.

Пример кода ниже

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-pars

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)) {

}

в Connect До сих пор нет Enum.TryParse) и получил ответ, указывающий на возможное включение в следующую структуру после .NET 3.5. Вам придется реализовать предложенные обходные пути.

Catch, вам нужно использовать IsDefined или GetNames ... Вот несколько примеров ... они в основном все одинаковые, первый обрабатывает обнуляемые перечисления. Я предпочитаю второй, так как это расширение для строк, а не для перечислений ... но вы можете смешивать их как хотите!

Www.objectreference.net / пост / Enum-TryParse-Extension-Method.aspx Flatlinerdoa.spaces.live.com / блог / СНН! 17124D03A9A052B0! 605.entry Mironabramson.com / блог / запись / 2008/03 / Другая-версия-для-недостающего-метод-EnumTryParse.aspx Lazyloading.blogspot.com / 2008/04 / enumtryparse-с-нетто-35-extension.html

потому что тип Enum не известен до времени выполнения. TryParse, использующий ту же методологию, что и метод Date.TryParse, выдает явную ошибку преобразования для параметра ByRef.

Я предлагаю сделать что-то вроде этого:

//1 line call to get value
MyEnums enumValue = (Sections)EnumValue(typeof(Sections), myEnumTextValue, MyEnums.SomeEnumDefault);

//Put this somewhere where you can reuse
public static object EnumValue(System.Type enumType, string value, object NotDefinedReplacement)
{
    if (Enum.IsDefined(enumType, value)) {
        return Enum.Parse(enumType, value);
    } else {
        return Enum.Parse(enumType, NotDefinedReplacement);
    }
}
 supercat18 дек. 2012 г., 19:48
ДляTry методы, результаты которых могут быть типами значений, или гдеnull может быть законным результатом (например,Dictionary.TryGetValue, which has both such traits), the normal pattern is for a Попробуй вернуть методbool и передайте результат какout параметр. Для тех, которые возвращают типы классов, гдеnull не является действительным результатом, нет проблем с использованиемnull вернуться, чтобы указать сбой.

Этот метод преобразует тип enum:

  public static TEnum ToEnum<TEnum>(object EnumValue, TEnum defaultValue)
    {
        if (!Enum.IsDefined(typeof(TEnum), EnumValue))
        {
            Type enumType = Enum.GetUnderlyingType(typeof(TEnum));
            if ( EnumValue.GetType() == enumType )
            {
                string name = Enum.GetName(typeof(HLink.ViewModels.ClaimHeaderViewModel.ClaimStatus), EnumValue);
                if( name != null)
                    return (TEnum)Enum.Parse(typeof(TEnum), name);
                return defaultValue;
            }
        }
        return (TEnum)Enum.Parse(typeof(TEnum), EnumValue.ToString());
    } 

Он проверяет базовый тип и получает его имя для анализа. Если все не удается, он вернет значение по умолчанию.

 Manish Basantani09 июн. 2010 г., 18:28
что это делает "Enum.GetName (typeof (HLink.ViewModels.ClaimHeaderViewModel.ClaimStatus), EnumValue)" Возможно, некоторая зависимость от вашего локального кода.

GetNames (), и мы все знаем, что исключения не должны использоваться для общей логики приложения:)

 Thorarin04 июл. 2009 г., 19:21
Это не тоттольк путь. 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.

 Anthony Johnston19 авг. 2010 г., 10:33
Также на IsDefined @ нет случая игнорирован
 Nader Shirazie04 июл. 2009 г., 21:51
Обратные ссылки в Enum.IsDefined: Blogs.msdn.com / Brada / архив / 2003/11/29 / 50903.aspx
 Thorarin05 июл. 2009 г., 03:13
GetNames () имеет те же недостатки ...
 Thorarin19 авг. 2010 г., 12:17
@ Энтони: если вы хотите поддерживать нечувствительность к регистру, вам понадобитсяGetNames. Внутренне все эти методы (включаяParse) использоватьGetHashEntry, который делает реальное отражение - один раз. С другой стороны, в .NET 4.0 есть TryParse, и он тоже универсальный:)
 Thomas Levesque04 июл. 2009 г., 20:08
Лучший ответ, который я видел до сих пор ... не пытайся и не лови, нет GetNames:)

Поскольку вы не знаете (кажется, что) тип перечисления заранее, первое выполнение может сгенерировать что-то, чем последующие выполнения могли бы воспользоваться.

Вы даже можете кэшировать результат Enum.GetNames ()

Вы пытаетесь оптимизировать процессор или память? Выдействительн нужно

 Manish Basantani04 июл. 2009 г., 19:31
Идея заключается в оптимизации процессора. Согласитесь, что я могу сделать это за плату памяти. Но это не решение, которое я ищу. Благодарность

Ваш ответ на вопрос