Frage

Was ist der beste Weg, um konvertieren eine Zeichenfolge in eine enumeration value in C#?

Ich habe eine HTML-select-tag mit die Werte einer Aufzählung.Wenn die Seite gepostet wird, will ich zum abholen der Wert wird in form einer Zeichenkette) und konvertieren Sie es in der enumeration value.

In einer idealen Welt könnte ich so etwas wie dies tun:

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

doch das ist kein Gültiger code.

War es hilfreich?

Lösung

In .NET Core-und .NET >4 es ist ein generisches Analyse-Methode:

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

Diese enthält auch C#7 die neue inline out Variablen, so bedeutet dies try-parse, die Umstellung auf die explizite enum-Typ und initialisiert+füllt myStatus - variable.

Wenn Sie Zugang zu C#7 und der Letzte .NETTO-dies ist der beste Weg.

Ursprüngliche Antwort

In .NET, es ist ziemlich hässlich (bis 4 oder oben):

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

Ich Neige dazu, um dies zu vereinfachen mit:

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

Dann kann ich tun:

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

Eine Möglichkeit vorgeschlagen, in den Kommentaren ist eine Erweiterung hinzufügen, die ist einfach genug:

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

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

Schließlich, möchten Sie vielleicht, um eine Standard-enum zu verwenden, wenn die Zeichenfolge nicht analysiert werden kann:

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

Die macht der Aufruf:

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

Allerdings würde ich vorsichtig sein, das hinzufügen einer Erweiterung Methode wie diese string wie (ohne namespace control) erscheint es auf allen Instanzen string ob Sie im Besitz einer enum oder nicht (also 1234.ToString().ToEnum(StatusEnum.None) wäre gültig, aber unsinnig) .Es ist oft am besten zu vermeiden, überladen Microsoft ' s core-Klassen mit zusätzlichen Methoden, die sich nur in sehr speziellen Kontexten, es sei denn, Ihre gesamte Entwicklung team hat ein sehr gutes Verständnis von dem, was Erweiterungen tun.

Andere Tipps

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

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

Es kann vereinfacht werden, noch weiter mit C# 7.0 parameter Typ inlining:

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

Beachten Sie, dass die Leistung von Enum.Parse() ist schrecklich, denn es ist implementiert über Reflexion.(Das gleiche gilt von Enum.ToString, die geht den anderen Weg.)

Wenn Sie müssen konvertieren von Zeichenfolgen, um Enumerationen in performance-sensitive code, Ihre beste Wette ist, zu erstellen Dictionary<String,YourEnum> beim Start und der Nutzung, dass Ihre conversions.

Sie sind auf der Suche für Enum.Analysieren.

SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");

Sie können verwenden extension Methoden jetzt:

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

Und rufen Sie Sie an, indem Sie den folgenden code (hier FilterType ist ein enum-Typ):

FilterType filterType = type.ToEnum<FilterType>();
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);

Also, wenn Sie hatte eine Enumeration namens Stimmung würde es so Aussehen:

   enum Mood
   {
      Angry,
      Happy,
      Sad
   } 

   // ...
   Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
   Console.WriteLine("My mood is: {0}", m.ToString());

VORSICHT:

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

Enum.(Try)Parse() akzeptiert mehrere, durch Komma getrennte Argumente, und kombiniert Sie mit binary 'oder' |.Sie können dies deaktivieren, und meiner Meinung nach sind Sie fast nie wollen es.

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

Auch wenn Three wurde nicht definiert, x würde noch erhalten int-Wert 3.Das ist sogar noch schlimmer:Enum.Parse() können Sie einen Wert, der nicht einmal den für den enum!

Ich würde nicht wollen, erleben die Konsequenzen der Benutzer, willentlich oder unwillentlich, das auslösen dieses Verhaltens.

Darüber hinaus, wie von anderen erwähnt, ist die Leistung weniger als ideal für große enums, nämlich linear in der Anzahl der möglichen Werte.

Ich schlage vor, die folgenden:

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

Enum.Analysieren ist dein Freund:

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

Können Sie verlängern die akzeptierte Antwort mit einem default-Wert zu vermeiden Ausnahmen:

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

Dann rufen Sie Sie wie:

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

Wir konnten nicht davon ausgehen, perfekt gültige Eingabe, und ging mit dieser variation von @Keith ' s Antwort:

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;
}
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str) 
{ 
    return (T) Enum.Parse(typeof(T), str);
}

Analysiert string TEnum ohne try/catch und ohne TryParse () - Methode aus .NET 4.5

/// <summary>
/// Parses string to TEnum without try/catch and .NET 4.5 TryParse()
/// </summary>
public static bool TryParseToEnum<TEnum>(string probablyEnumAsString_, out TEnum enumValue_) where TEnum : struct
{
    enumValue_ = (TEnum)Enum.GetValues(typeof(TEnum)).GetValue(0);
    if(!Enum.IsDefined(typeof(TEnum), probablyEnumAsString_))
        return false;

    enumValue_ = (TEnum) Enum.Parse(typeof(TEnum), probablyEnumAsString_);
    return true;
}

Super einfach, code mit TryParse:

var value = "Active";

StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
    status = StatusEnum.Unknown;

Ich mag die extension-Methode Lösung..

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

Hier unten meine Umsetzung mit tests.

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
        }
public static T ParseEnum<T>(string value)            //function declaration  
{
    return (T) Enum.Parse(typeof(T), value);
}

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

====================Ein Komplettes Programm====================

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.

Ich benutzte Klasse (stark typisierte version von Enum mit Analyse-und performance-Verbesserungen).Ich fand es auf GitHub, und es sollte funktionieren für .NET 3.5 zu.Es hat einige Speicher-overhead, da es puffert ein Wörterbuch.

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

Der Beitrag ist Enums – Bessere syntax, verbesserte Leistung und TryParse in NET 3.5.

Und code:https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs

Für die Leistung dieser könnte helfen:

    private static Dictionary<Type, Dictionary<string, object>> dicEnum = new Dictionary<Type, Dictionary<string, object>>();
    public static T ToEnum<T>(this string value, T defaultValue)
    {
        var t = typeof(T);
        Dictionary<string, object> dic;
        if (!dicEnum.ContainsKey(t))
        {
            dic = new Dictionary<string, object>();
            dicEnum.Add(t, dic);
            foreach (var en in Enum.GetValues(t))
                dic.Add(en.ToString(), en);
        }
        else
            dic = dicEnum[t];
        if (!dic.ContainsKey(value))
            return defaultValue;
        else
            return (T)dic[value];
    }

Ich fand, dass hier der Fall mit enum-Werten EnumMember Wert wurde nicht berücksichtigt.Also hier gehen wir:

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

Und das Beispiel, dass enum:

public enum OracleInstanceStatus
{
    Unknown = -1,
    Started = 1,
    Mounted = 2,
    Open = 3,
    [EnumMember(Value = "OPEN MIGRATE")]
    OpenMigrate = 4
}

Verwenden Sie die Enum.Analysieren, um die Objekt-Wert von Enum, nach, dass, Sie haben zu ändern die Wert des Objektes zu bestimmten enum-Wert.Casting für enum-Wert kann unter Verwendung von Umwandeln.ChangeType.Bitte haben Sie einen Blick auf folgende code-snippet

public T ConvertStringValueToEnum<T>(string valueToParse){
    return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}

Versuchen Sie dieses Beispiel:

 public static T GetEnum<T>(string model)
    {
        var newModel = GetStringForEnum(model);

        if (!Enum.IsDefined(typeof(T), newModel))
        {
            return (T)Enum.Parse(typeof(T), "None", true);
        }

        return (T)Enum.Parse(typeof(T), newModel.Result, true);
    }

    private static Task<string> GetStringForEnum(string model)
    {
        return Task.Run(() =>
        {
            Regex rgx = new Regex("[^a-zA-Z0-9 -]");
            var nonAlphanumericData = rgx.Matches(model);
            if (nonAlphanumericData.Count < 1)
            {
                return model;
            }
            foreach (var item in nonAlphanumericData)
            {
                model = model.Replace((string)item, "");
            }
            return model;
        });
    }

In diesem Beispiel senden Sie jede saite, und legen Sie Ihre Enum.Wenn Ihr Enum hatte die Daten, die Sie wollte, zurück, als der Enum Typ.

        <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
public TEnum ToEnum<TEnum>(this string value, TEnum defaultValue){
if (string.IsNullOrEmpty(value))
    return defaultValue;

return Enum.Parse(typeof(TEnum), value, true);}
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top