Comment convertir une chaîne en enum en C#?
Quelle est la meilleure façon de convertir une chaîne de caractères en valeur d'énumération en C#?
j'ai une balise HTML select contenant les valeurs d'une énumération. Quand la page est postée, je veux prendre la valeur (qui sera sous la forme d'une chaîne de caractères) et la convertir à la valeur d'énumération.
dans un monde idéal, je pourrais faire quelque chose comme ça:
StatusEnum MyStatus = StatusEnum.Parse("Active");
mais ce n'est pas un code valide.
20 réponses
.NET de Base et .NET >4 il y a un générique de la méthode d'analyse :
Enum.TryParse("Active", out StatusEnum myStatus);
Cela inclut également la nouvelle inline de C#7 out
variables, donc cela fait l'essai-parse, la conversion au type enum explicite et initialise+popule la variable myStatus
.
si vous avez accès à C#7 et le dernier .NET c'est la meilleure façon.
Réponse Originale À Cette Question
In .NET c'est plutôt moche (jusqu'à 4 ou ci-dessus):
StatusEnum MyStatus = (StatusEnum) Enum.Parse(typeof(StatusEnum), "Active", true);
j'ai tendance à simplifier avec:
public static T ParseEnum<T>(string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
je peux le faire:
StatusEnum MyStatus = EnumUtil.ParseEnum<StatusEnum>("Active");
une option suggérée dans les commentaires est d'ajouter une extension, ce qui est assez simple:
public static T ToEnum<T>(this string value)
{
return (T) Enum.Parse(typeof(T), value, true);
}
StatusEnum MyStatus = "Active".ToEnum<StatusEnum>();
enfin, vous pouvez avoir un enum par défaut à utiliser si la chaîne ne peut pas être analysée:
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;
}
ce qui fait de celui-ci appel:
StatusEnum MyStatus = "Active".ToEnum(StatusEnum.None);
cependant, je serais prudent d'ajouter une méthode d'extension comme celle-ci à string
car (sans contrôle de l'Espace-nom) elle apparaîtra sur toutes les instances de string
qu'elles contiennent ou non un enum (donc 1234.ToString().ToEnum(StatusEnum.None)
serait valide mais non logique) . Il est souvent préférable d'éviter D'encombrer les classes de base de Microsoft avec des méthodes supplémentaires qui ne s'appliquent que dans des contextes très spécifiques à moins que toute votre équipe de développement a une très bonne compréhension de ce que ces extensions le font.
Use Enum.TryParse<T>(String, T)
(≥ . net 4.0):
StatusEnum myStatus;
Enum.TryParse("Active", out myStatus);
il peut être encore simplifié avec C# 7.0 type de paramètre inlining :
Enum.TryParse("Active", out StatusEnum myStatus);
Note que la performance de l'Enum.Parse () est terrible, parce qu'il est mis en œuvre via la réflexion. (Il en va de même pour Enum.ToString, qui va dans l'autre sens.)
si vous avez besoin de convertir des chaînes en Enums en code sensible aux performances, votre meilleure chance est de créer un Dictionary<String,YourEnum>
au démarrage et de l'utiliser pour faire vos conversions.
vous cherchez Enum.Parse .
SomeEnum enum = (SomeEnum)Enum.Parse(typeof(SomeEnum), "EnumValue");
vous pouvez utiliser méthodes d'extension maintenant:
public static T ToEnum<T>(this string value, bool ignoreCase = true)
{
return (T) Enum.Parse(typeof (T), value, ignoreCase);
}
et vous pouvez les appeler par le code ci-dessous (ici, FilterType
est un type enum):
FilterType filterType = type.ToEnum<FilterType>();
object Enum.Parse(System.Type enumType, string value, bool ignoreCase);
donc si vous aviez un énum nommé mood il ressemblerait à ceci:
enum Mood
{
Angry,
Happy,
Sad
}
// ...
Mood m = (Mood) Enum.Parse(typeof(Mood), "Happy", true);
Console.WriteLine("My mood is: {0}", m.ToString());
attention:
enum Example
{
One = 1,
Two = 2,
Three = 3
}
Enum.(Try)Parse()
accepte plusieurs arguments séparés par des virgules, et les combine avec des arguments binaires 'ou' |
. Vous ne pouvez pas désactiver cette et à mon avis vous presque jamais le souhaitez.
var x = Enum.Parse("One,Two"); // x is now Three
même si Three
n'était pas défini, x
obtiendrait quand même la valeur int 3
. C'est encore pire: Enum.Parse() peut vous donner une valeur qui n'est pas même défini pour l'enum!
Je ne voudrais pas faire l'expérience des conséquences des utilisateurs, volontairement ou non, déclenchant ce comportement.
en outre, comme mentionné par d'autres, la performance est moins qu'idéal pour les grands énums, à savoir linéaire dans le nombre de valeurs possibles.
je suggère ce qui suit:
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.Analyser est votre ami:
StatusEnum MyStatus = (StatusEnum)Enum.Parse(typeof(StatusEnum), "Active");
vous pouvez étendre la réponse acceptée avec une valeur par défaut pour éviter les exceptions:
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;
}
}
alors vous l'appelez comme:
StatusEnum MyStatus = EnumUtil.ParseEnum("Active", StatusEnum.None);
nous ne pouvions pas supposer une entrée parfaitement valide, et sommes allés avec cette variation de la réponse de @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;
}
// str.ToEnum<EnumType>()
T static ToEnum<T>(this string str)
{
return (T) Enum.Parse(typeof(T), str);
}
Analyse de la chaîne de TEnum sans try/catch et sans TryParse() la méthode de .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;
}
essayez cet échantillon:
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;
});
}
dans cet exemple, vous pouvez envoyer chaque chaîne, et définir votre Enum
. Si votre Enum
avait des données que vous vouliez, retournez-les comme votre type Enum
.
GoodLock.
Super simple code à l'aide de TryParse:
var value = "Active";
StatusEnum status;
if (!Enum.TryParse<StatusEnum>(value, out status))
status = StatusEnum.Unknown;
j'aime la solution de la méthode d'extension..
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;
}
}
}
ci-dessous mon implémentation avec des 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
====================Un Programme Complet====================
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.
j'ai utilisé la classe (fortement typées version de Enum avec l'analyse et des améliorations de performances). Je l'ai trouvé sur GitHub, et ça devrait marcher pour .NET 3.5 aussi. Il a un peu de mémoire au-dessus de lui car il tamponne un dictionnaire.
StatusEnum MyStatus = Enum<StatusEnum>.Parse("Active");
Le blog est Enums – Meilleure syntaxe, l'amélioration de la performance et de TryParse NET 3.5 .
et code: https://github.com/damieng/DamienGKit/blob/master/CSharp/DamienG.Library/System/EnumT.cs
Pour la performance, ce qui pourrait aider:
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];
}
j'ai trouvé que le cas avec les valeurs enum qui ont la valeur EnumMember N'a pas été considéré. Nous y voilà:
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;
}
et exemple de cet enum:
public enum OracleInstanceStatus
{
Unknown = -1,
Started = 1,
Mounted = 2,
Open = 3,
[EnumMember(Value = "OPEN MIGRATE")]
OpenMigrate = 4
}
vous devez utiliser Enum.Parse pour obtenir la valeur de l'objet à partir D'Enum, après cela vous devez changer la valeur de l'objet en valeur d'enum spécifique. Casting to enum valeur peut être fait en utilisant Convert.ChangeType. S'il vous plaît jeter un oeil sur l'extrait de code suivant
public T ConvertStringValueToEnum<T>(string valueToParse){
return Convert.ChangeType(Enum.Parse(typeof(T), valueToParse, true), typeof(T));
}