web-dev-qa-db-ja.com

大文字と小文字を区別せずに列挙型が定義されているかどうかをテストするにはどうすればよいですか?

次のジェネリック静的メソッドはstringを取り、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
    }
}
34
Edward Tanguay
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);
    }
}
36
Darin Dimitrov

@Darinの回答に加えて、.NET 4.0では、Enum型にTryParseメソッドが追加されました。

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

覚えておくべき重要なことは、ParseとTryParseの動作には根本的な違いがあるということです。解析メソッドは例外をスローします。 TryParseメソッドはそうではありません。これは、多くのアイテムを解析しようとしている可能性があるかどうかを知るために非常に重要です。

29
Matthew Abbott

他の人が言っているように、_Enum.TryParse_を使用するだけで逃げることができるかもしれません。

ただし、文字列だけでなく変換できる、より堅牢で一般的な変換が必要な場合は、_Enum.IsDefined_も使用する必要があります。残念ながら、これはnot caseです。 -大文字と小文字を区別しません。

_Enum.TryParse_ is(可能性があります)大文字と小文字は区別されません。しかし、残念ながら、範囲外のintが通過する可能性があります。

したがって、解決策はそれらを一緒に使用することです(そして順序は重要です)。

私はまさにそれを行う拡張メソッドを書きました。 string、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;
        }
    }
}
_

私の拡張メソッドにはさらに多くのことがあります...デフォルトを指定でき、範囲外のintを適切に処理し、大文字と小文字を完全に区別しません。興味があればもっと投稿できます。

6

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;
}

HTH

5
cyberenergy

代わりに Enum.TryParse を使用してください:

T val;

if(Enum.TryParse(text, true, out val))
    return val;
else 
    return default(T);
5
Justin Niessner
    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);
    }
1
Chandra Malla
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;
}
0
maxwellb

同様の懸念があり、.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
David Pine

テキストを列挙型文字列と同じ大文字小文字にする:

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
caughtouttoo

最初に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
CSharper