Как я могу проверить, определено ли перечисление или нет, игнорируя регистр? - PullRequest
32 голосов
/ 01 июля 2010

Следующий общий статический метод принимает строку и возвращает enum .

Прекрасно игнорирует регистр , поскольку я установил для параметра ignoreCase значение true.

Однако я также хочу проверить, существует ли перечисление , но метод enum.IsDefined для этого, похоже, не имеет параметра ignoreCase .

Как я могу проверить, определено ли перечисление или нет и в том же регистре игнорирования?

using System;

namespace TestEnum2934234
{
    class Program
    {
        static void Main(string[] args)
        {
            LessonStatus lessonStatus = StringHelpers.ConvertStringToEnum<LessonStatus>("prepared");
            ReportStatus reportStatus = StringHelpers.ConvertStringToEnum<ReportStatus>("finished");

            Console.WriteLine(lessonStatus.ToString());
            Console.WriteLine(reportStatus.ToString());
            Console.ReadLine();
        }
    }

    public static class StringHelpers
    {
        public static T ConvertStringToEnum<T>(string text)
        {
            if (Enum.IsDefined(typeof(T), text)) //does not have ignoreCase parameter
                return (T)Enum.Parse(typeof(T), text, true);
            else
                return default(T);
        }
    }

    public enum LessonStatus
    {
        Defined,
        Prepared,
        Practiced,
        Recorded
    }

    public enum ReportStatus
    {
        Draft,
        Revising,
        Finished
    }
}

Ответы [ 10 ]

36 голосов
/ 01 июля 2010
public enum MyEnum
{
    Bar,
    Foo
}

class Program
{
    static void Main(string[] args)
    {
        var containsFoo = Enum.GetNames(typeof(MyEnum)).Any(x => x.ToLower() == "foo");
        Console.WriteLine(containsFoo);
    }
}
29 голосов
/ 01 июля 2010

Наряду с ответом @ Darin, в .NET 4.0 тип Enum теперь имеет метод TryParse:

MyEnum result;
Enum.TryParse("bar", true, out result);

Важно помнить, что в поведении Parse vs есть фундаментальное различиеTryParse.Методы разбора будут генерировать исключения.TryParse методов не будет.Это очень важно знать, если вы пытаетесь разобрать много элементов.

5 голосов
/ 10 марта 2015

Возможно, вам удастся сойти с рук, просто используя Enum.TryParse, как уже говорили другие.

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

Enum.TryParse это (может быть) case-нечувствительны.Но, к сожалению, он позволяет выходить за пределы диапазона!

Так что решение состоит в том, чтобы использовать их вместе (и порядок важен).

Я написал метод расширения, который делаеттолько то.Это позволяет преобразование из строки, int / int? И любой другой Enum / Enum?наберите вот так:

string value1 = "Value1";
Enum2 enum2 = value1.ParseToEnum<Enum2>();
Debug.Assert(enum2.ToString() == value1);

Enum1 enum1 = Enum1.Value1;
enum2 = enum1.ParseToEnum<Enum2>();
Debug.Assert(enum2.ToString() == enum1.ToString());

int value2 = 1;
enum2 = value2.ParseToEnum<Enum2>();
Debug.Assert(enum2.GetHashCode() == value2);

Вот суть метода.Это часть преобразования, которая отвечает на ваш вопрос.Переменная value имеет тип object из-за моих «перегрузок», которые принимают разные типы в качестве основного входа (см. Выше), но вы можете сделать это с переменной типа string, просто отлично, если это всеВы хотите (очевидно, изменив value.ToString() на value).

if (value != null)
{
    TEnum result;
    if (Enum.TryParse(value.ToString(), true, out result))
    {
        // since an out-of-range int can be cast to TEnum, double-check that result is valid
        if (Enum.IsDefined(typeof(TEnum), result.ToString()))
        {
            return result;
        }
    }
}

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

5 голосов
/ 14 февраля 2013

Я использую Compact Framework 3.5 и:

Enum.TryParse

... не существует. Он имеет:

Enum.IsDefined

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

public bool TryParse<TEnum>(string value, bool ignoreCase, ref TEnum result) where TEnum : struct
{
    bool parsed;
    try
    {
        result = (TEnum)Enum.Parse(typeof(TEnum), value, ignoreCase);
        parsed = true;
    }
    catch { }
    return parsed;
}

НТН

5 голосов
/ 01 июля 2010

Используйте Enum.TryParse вместо:

T val;

if(Enum.TryParse(text, true, out val))
    return val;
else 
    return default(T);
1 голос
/ 07 октября 2012
    enum DaysCollection
    {
     sunday,
     Monday,
     Tuesday,
     Wednesday,
     Thursday,
     Friday,
     Saturday
    }

    public bool isDefined(string[] arr,object obj)
    {
        bool result=false;
        foreach (string enu in arr)
        {
              result = string.Compare(enu, obj.ToString(), true) == 0;
              if (result)
                  break;

        }
        return result;


    }

    private void button1_Click(object sender, EventArgs e)
    {
        object obj = "wednesday";
        string[] arr = Enum.GetNames(typeof(DaysCollection)).ToArray();

        isDefined(arr,obj);
    }
0 голосов
/ 25 декабря 2018

Сначала используйте метод Enum.TryParse, чтобы получить объект типа T, затем передайте этот объект методу Enum.IsDefined:

private static T ConvertStringToEnum<T>(string stringValue) where T : struct
{
    if (System.Enum.TryParse(stringValue, out T result))
    {
        if (System.Enum.IsDefined(typeof(T), result) || result.ToString().Contains(","))
            return result;

        throw new System.Exception($"{stringValue} is not an underlying value of the {typeof(T).FullName} enumeration.");
    }

    throw new System.Exception($"{stringValue} is not a member of the {typeof(T).FullName} enumeration.");
}
0 голосов
/ 05 октября 2017

У меня была похожая проблема, и я использовал комбинацию .Enum.TryPase (с флагом без учета регистра, установленным как true) и Enum.IsDefined. Рассмотрим следующее как упрощение вашего вспомогательного класса:

public static class StringHelpers
{
    public static T ConvertStringToEnum<T>(string text)
    {
        T result;
        return Enum.TryParse(text, true, out result)
            && Enum.IsDefined(result.ToString())
                ? result
                : default(T);
    }
}

И пока мы работаем над этим, поскольку вспомогательный класс является статическим, а метод статическим - мы можем сделать это методом расширения на string.

public static class StringExtensions
{
    public static TEnum ToEnum<TEnum>(this string text)
        where TEnum : struct, IComparable, IFormattable, IConvertible 
    {
        TEnum result = default(TEnum);
        return !string.IsNullOrWhiteSpace(text) 
            && Enum.TryParse(text, true, out result)
            && Enum.IsDefined(typeof(TEnum), result.ToString())
                ? result
                : default(TEnum);
    }
}

Здесь я создал .NET Fiddle, который наглядно демонстрирует это.

0 голосов
/ 15 января 2014

Сделать текст таким же регистром, что и строка enum:

enum FileExts
{
  jpg,
  pdf
}

if (Enum.IsDefined(typeof(T), text.tolower())) //does not have ignoreCase parameter
    return (T)Enum.Parse(typeof(T), text, true);
else
    return default(T);
0 голосов
/ 01 июля 2010
public static T ConvertStringToEnum<T>(string text)
{
    T returnVal;
    try
    {
        returnVal = (T) Enum.Parse( typeof(T), text, true );
    }
    catch( ArgumentException )
    {
        returnVal = default(T);
    }
    return returnVal;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...