1098

C#で文字列を列挙値に変換する最良の方法は何ですか?

列挙値を含む HTML select タグがあります。ページが投稿されたら、値 (文字列の形式になります) を取得し、対応する列挙値に変換したいと考えています。

理想的な世界では、次のようなことができます。

StatusEnum MyStatus = StatusEnum.Parse("Active");

しかし、それは有効なコードではありません。

4

28 に答える 28

1833

.NET Core および .NET Framework ≥4.0には、汎用の解析メソッドがあります。

Enum.TryParse("Active", out StatusEnum myStatus);

これには C#7 の新しいインラインout変数も含まれているため、try-parse を実行し、明示的な列挙型に変換し、myStatus変数を初期化して入力します。

C#7 と最新の .NET にアクセスできる場合は、これが最善の方法です。

元の回答

.NETではかなり醜いです(4以上まで):

StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);

私はこれを次のように単純化する傾向があります。

public static T ParseEnum<T>(string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

それから私はすることができます:

StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");

コメントで提案されているオプションの 1 つは、拡張機能を追加することです。これは非常に簡単です。

public static T ToEnum<T>(this string value)
{
    return (T) Enum.Parse(typeof(T), value, true);
}

StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();

最後に、文字列を解析できない場合に使用するデフォルトの列挙型が必要になる場合があります。

public static T ToEnum<T>(this string value, T defaultValue) 
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    T result;
    return Enum.TryParse<T>(value, true, out result) ? result : defaultValue;
}

これが呼び出しになります:

StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);

ただし、このような拡張メソッドstringを (名前空間制御なしで)string列挙型を保持しているかどうかのすべてのインスタンスに表示されるように追加することに注意します (1234.ToString().ToEnum(StatusEnum.None)有効ですが無意味です)。開発チーム全体がこれらの拡張機能の機能を十分に理解している場合を除き、非常に特定のコンテキストでのみ適用される追加のメソッドで Microsoft のコア クラスを乱雑にしないことが最善の方法であることがよくあります。

于 2008-08-19T12:54:28.533 に答える
372

使用Enum.TryParse<T>(String, T)(≥ .NET 4.0):

StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);

C# 7.0 のパラメーター型のインライン化を使用すると、さらに単純化できます。

Enum.TryParse("Active", out StatusEnum myStatus);
于 2013-12-05T08:22:38.090 に答える
225

リフレクションを介して実装されているため、 のパフォーマンスEnum.Parse()はひどいことに注意してください。(Enum.ToString逆の場合も同様です。)

パフォーマンスが重要なコードで文字列を Enum に変換する必要がある場合、最善の策はDictionary<String,YourEnum>、起動時に を作成し、それを使用して変換を行うことです。

于 2008-09-02T02:27:07.447 に答える
113

Enum.Parseを探しています。

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
于 2008-08-19T12:53:52.747 に答える
28

注意:

enum Example
{
    One = 1,
    Two = 2,
    Three = 3
}

Enum.(Try)Parse() 複数のカンマ区切りの引数を受け入れ、それらをバイナリ 'or' で結合します|。これを無効にすることはできません。私の意見では、これを無効にすることはほとんどありません。

var x = Enum.Parse("One,Two"); // x is now Three

Threeが定義されていなくてもx、 int value を取得します3。それはさらに悪いことです: Enum.Parse() は、列挙型に対して定義されていない値を与える可能性があります!

ユーザーが意図的または不本意に、この動作をトリガーした結果を経験したくありません。

さらに、他の人が述べたように、パフォーマンスは大きな列挙型、つまり可能な値の数が線形の場合には理想的ではありません。

次のことをお勧めします。

    public static bool TryParse<T>(string value, out T result)
        where T : struct
    {
        var cacheKey = "Enum_" + typeof(T).FullName;

        // [Use MemoryCache to retrieve or create&store a dictionary for this enum, permanently or temporarily.
        // [Implementation off-topic.]
        var enumDictionary = CacheHelper.GetCacheItem(cacheKey, CreateEnumDictionary<T>, EnumCacheExpiration);

        return enumDictionary.TryGetValue(value.Trim(), out result);
    }

    private static Dictionary<string, T> CreateEnumDictionary<T>()
    {
        return Enum.GetValues(typeof(T))
            .Cast<T>()
            .ToDictionary(value => value.ToString(), value => value, StringComparer.OrdinalIgnoreCase);
    }
于 2015-12-14T12:31:47.580 に答える
22
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

したがって、mood という名前の列挙型がある場合、次のようになります。

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());
于 2008-08-19T12:58:57.730 に答える
16

Enum.Parseはあなたの友達です:

StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
于 2008-08-19T12:55:31.743 に答える
13

受け入れられた回答をデフォルト値で拡張して、例外を回避できます。

public static T ParseEnum<T>(string value, T defaultValue) where T : struct
{
    try
    {
        T enumValue;
        if (!Enum.TryParse(value, true, out enumValue))
        {
            return defaultValue;
        }
        return enumValue;
    }
    catch (Exception)
    {
        return defaultValue;
    }
}

次に、次のように呼び出します。

StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);

デフォルト値が列挙型でない場合、Enum.TryParse は失敗し、キャッチされる例外をスローします。

コードの多くの場所でこの関数を何年も使用した後、この操作がパフォーマンスを犠牲にするという情報を追加するのは良いことかもしれません!

于 2014-12-09T11:43:43.907 に答える
11

完全に有効な入力を想定することはできず、@Keith の回答の次のバリエーションを使用しました。

public static TEnum ParseEnum<TEnum>(string value) where TEnum : struct
{
    TEnum tmp; 
    if (!Enum.TryParse<TEnum>(value, true, out tmp))
    {
        tmp = new TEnum();
    }
    return tmp;
}
于 2012-08-30T15:07:10.443 に答える
7
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}
于 2008-08-19T13:13:38.277 に答える
7

これがいつ追加されたのかはわかりませんが、Enum クラスには現在

Parse<TEnum>(stringValue)

問題の例では次のように使用されます。

var MyStatus = Enum.Parse<StatusEnum >("Active")

または大文字と小文字を無視する:

var MyStatus = Enum.Parse<StatusEnum >("active", true)

これが使用する逆コンパイルされたメソッドは次のとおりです。

    [NullableContext(0)]
    public static TEnum Parse<TEnum>([Nullable(1)] string value) where TEnum : struct
    {
      return Enum.Parse<TEnum>(value, false);
    }

    [NullableContext(0)]
    public static TEnum Parse<TEnum>([Nullable(1)] string value, bool ignoreCase) where TEnum : struct
    {
      TEnum result;
      Enum.TryParse<TEnum>(value, ignoreCase, true, out result);
      return result;
    }
于 2019-11-27T18:34:51.117 に答える
4

私は拡張メソッドソリューションが好きです..

namespace System
{
    public static class StringExtensions
    {

        public static bool TryParseAsEnum<T>(this string value, out T output) where T : struct
        {
            T result;

            var isEnum = Enum.TryParse(value, out result);

            output = isEnum ? result : default(T);

            return isEnum;
        }
    }
}

ここでは、テストを使用した実装を以下に示します。

using static Microsoft.VisualStudio.TestTools.UnitTesting.Assert;
using static System.Console;

private enum Countries
    {
        NorthAmerica,
        Europe,
        Rusia,
        Brasil,
        China,
        Asia,
        Australia
    }

   [TestMethod]
        public void StringExtensions_On_TryParseAsEnum()
        {
            var countryName = "Rusia";

            Countries country;
            var isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsTrue(isCountry);
            AreEqual(Countries.Rusia, country);

            countryName = "Don't exist";

            isCountry = countryName.TryParseAsEnum(out country);

            WriteLine(country);

            IsFalse(isCountry);
            AreEqual(Countries.NorthAmerica, country); // the 1rst one in the enumeration
        }
于 2015-10-01T21:57:29.500 に答える
2

ここでは、EnumMember 値を持つ列挙値のケースが考慮されていないことがわかりました。だからここに行きます:

using System.Runtime.Serialization;

public static TEnum ToEnum<TEnum>(this string value, TEnum defaultValue) where TEnum : struct
{
    if (string.IsNullOrEmpty(value))
    {
        return defaultValue;
    }

    TEnum result;
    var enumType = typeof(TEnum);
    foreach (var enumName in Enum.GetNames(enumType))
    {
        var fieldInfo = enumType.GetField(enumName);
        var enumMemberAttribute = ((EnumMemberAttribute[]) fieldInfo.GetCustomAttributes(typeof(EnumMemberAttribute), true)).FirstOrDefault();
        if (enumMemberAttribute?.Value == value)
        {
            return Enum.TryParse(enumName, true, out result) ? result : defaultValue;
        }
    }

    return Enum.TryParse(value, true, out result) ? result : defaultValue;
}

そしてその列挙型の例:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}
于 2016-10-04T16:40:31.027 に答える
2
public static T ParseEnum<T>(string value)            //function declaration  
{
    return (T) Enum.Parse(typeof(T), value);
}

Importance imp = EnumUtil.ParseEnum<Importance>("Active");   //function call

====================完全なプログラム====================

using System;

class Program
{
    enum PetType
    {
    None,
    Cat = 1,
    Dog = 2
    }

    static void Main()
    {

    // Possible user input:
    string value = "Dog";

    // Try to convert the string to an enum:
    PetType pet = (PetType)Enum.Parse(typeof(PetType), value);

    // See if the conversion succeeded:
    if (pet == PetType.Dog)
    {
        Console.WriteLine("Equals dog.");
    }
    }
}
-------------
Output

Equals dog.
于 2015-08-18T05:28:07.893 に答える
2

私はクラスを使用しました (解析とパフォーマンスが向上した Enum の厳密に型指定されたバージョン)。GitHub で見つけましたが、.NET 3.5 でも動作するはずです。ディクショナリをバッファリングするため、メモリ オーバーヘッドが発生します。

StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");

ブログ投稿はEnums – Better syntax, Improvement performance and TryParse in NET 3.5です。

コード: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs

于 2015-07-01T09:39:48.757 に答える
2
public TEnum ToEnum<TEnum>(this string value, TEnum defaultValue){
if (string.IsNullOrEmpty(value))
    return defaultValue;

return Enum.Parse(typeof(TEnum), value, true);}
于 2019-05-22T07:19:51.063 に答える
1
        <Extension()>
    Public Function ToEnum(Of TEnum)(ByVal value As String, ByVal defaultValue As TEnum) As TEnum
        If String.IsNullOrEmpty(value) Then
            Return defaultValue
        End If

        Return [Enum].Parse(GetType(TEnum), value, True)
    End Function
于 2019-05-22T07:15:54.777 に答える