Risposte:
Da una stringa:
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString);
// The foo.ToString().Contains(",") check is necessary for enumerations marked with an [Flags] attribute
if (!Enum.IsDefined(typeof(YourEnum), foo) && !foo.ToString().Contains(","))
{
throw new InvalidOperationException($"{yourString} is not an underlying value of the YourEnum enumeration.")
}
Da un int:
YourEnum foo = (YourEnum)yourInt;
Aggiornare:
Dal numero puoi anche
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
var result = Enum.TryParse(yourString, out yourEnum)
oggigiorno (e controllare il risultato per determinare se la conversione non è riuscita).
Enum.Parse
true
YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
Basta lanciarlo:
MyEnum e = (MyEnum)3;
Puoi verificare se è nell'intervallo usando Enum.IsDefined :
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Enum.IsDefined
, tieni presente che può essere pericoloso: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
IsDefined
per controllare i valori di input, ti lasci vulnerabile alle persone che aggiungono nuovi valori di enum in seguito che passerebbero un IsDefined
controllo (dal momento che il nuovo esiste un valore nel nuovo codice), ma potrebbe non funzionare con il codice originale che hai scritto. È quindi più sicuro specificare esplicitamente i valori enum che il tuo codice è in grado di gestire.
In alternativa, utilizzare un metodo di estensione invece di una riga:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
Uso:
Color colorEnum = "Red".ToEnum<Color>();
O
string color = "Red";
var colorEnum = color.ToEnum<Color>();
System.String
sembra inquinamento dello spazio dei nomi
Penso che per ottenere una risposta completa, le persone devono sapere come funzionano gli enum internamente in .NET.
Come funzionano le cose
Un enum in .NET è una struttura che mappa un set di valori (campi) su un tipo base (il valore predefinito è int
). Tuttavia, puoi effettivamente scegliere il tipo integrale a cui l'enum è associato:
public enum Foo : short
In questo caso, l'enum è mappato sul short
tipo di dati, il che significa che verrà archiviato in memoria come short e si comporterà come short quando lo lanci e lo usi.
Se lo guardi da un punto di vista di IL, un enum (normale, int) si presenta così:
.class public auto ansi serializable sealed BarFlag extends System.Enum
{
.custom instance void System.FlagsAttribute::.ctor()
.custom instance void ComVisibleAttribute::.ctor(bool) = { bool(true) }
.field public static literal valuetype BarFlag AllFlags = int32(0x3fff)
.field public static literal valuetype BarFlag Foo1 = int32(1)
.field public static literal valuetype BarFlag Foo2 = int32(0x2000)
// and so on for all flags or enum values
.field public specialname rtspecialname int32 value__
}
Ciò che dovrebbe attirare la tua attenzione qui è che value__
è memorizzato separatamente dai valori enum. Nel caso dell'enum Foo
sopra, il tipo di value__
è int16. Questo in pratica significa che puoi archiviare quello che vuoi in un enum, purché i tipi corrispondano .
A questo punto vorrei sottolineare che si System.Enum
tratta di un tipo di valore, il che significa sostanzialmente che BarFlag
occuperà 4 byte in memoria e ne Foo
occuperà 2, ad esempio la dimensione del tipo sottostante (in realtà è più complicato di così, ma Hey...).
La risposta
Quindi, se si dispone di un numero intero che si desidera associare a un enum, il runtime deve solo fare 2 cose: copiare i 4 byte e nominarlo con qualcos'altro (il nome dell'enum). La copia è implicita perché i dati sono archiviati come tipo di valore: ciò significa sostanzialmente che se si utilizza un codice non gestito, è possibile scambiare semplicemente enumerazioni e numeri interi senza copiare i dati.
Per renderlo sicuro, penso che sia una buona pratica sapere che i tipi sottostanti sono gli stessi o implicitamente convertibili e per garantire che i valori enum esistano (non sono controllati per impostazione predefinita!).
Per vedere come funziona, prova il seguente codice:
public enum MyEnum : int
{
Foo = 1,
Bar = 2,
Mek = 5
}
static void Main(string[] args)
{
var e1 = (MyEnum)5;
var e2 = (MyEnum)6;
Console.WriteLine("{0} {1}", e1, e2);
Console.ReadLine();
}
Nota che anche il casting e2
funziona! Dal punto di vista del compilatore sopra questo ha senso: il value__
campo è semplicemente riempito con 5 o 6 e quando le Console.WriteLine
chiamate ToString()
, il nome di e1
viene risolto mentre il nome di e2
non lo è.
Se non è quello che intendevi, usa Enum.IsDefined(typeof(MyEnum), 6)
per verificare se il valore che stai lanciando viene mappato su un enum definito.
Nota anche che sono esplicito sul tipo di base dell'enum, anche se il compilatore lo controlla. Lo sto facendo per assicurarmi di non incappare in sorprese lungo la strada. Per vedere queste sorprese in azione, puoi usare il seguente codice (in realtà ho visto che ciò accade molto nel codice del database):
public enum MyEnum : short
{
Mek = 5
}
static void Main(string[] args)
{
var e1 = (MyEnum)32769; // will not compile, out of bounds for a short
object o = 5;
var e2 = (MyEnum)o; // will throw at runtime, because o is of type int
Console.WriteLine("{0} {1}", e1, e2);
Console.ReadLine();
}
int
! = short
, Verrà lanciato (unboxing fallisce). Se lo fai object o = (short)5;
, funzionerà, perché i tipi corrisponderanno. Non si tratta della gamma, è davvero del tipo.
Prendi il seguente esempio:
int one = 1;
MyEnum e = (MyEnum)one;
Sto usando questo pezzo di codice per lanciare int nel mio enum:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
La trovo la soluzione migliore.
Di seguito è una bella classe di utilità per Enums
public static class EnumHelper
{
public static int[] ToIntArray<T>(T[] value)
{
int[] result = new int[value.Length];
for (int i = 0; i < value.Length; i++)
result[i] = Convert.ToInt32(value[i]);
return result;
}
public static T[] FromIntArray<T>(int[] value)
{
T[] result = new T[value.Length];
for (int i = 0; i < value.Length; i++)
result[i] = (T)Enum.ToObject(typeof(T),value[i]);
return result;
}
internal static T Parse<T>(string value, T defaultValue)
{
if (Enum.IsDefined(typeof(T), value))
return (T) Enum.Parse(typeof (T), value);
int num;
if(int.TryParse(value,out num))
{
if (Enum.IsDefined(typeof(T), num))
return (T)Enum.ToObject(typeof(T), num);
}
return defaultValue;
}
}
Per i valori numerici, questo è più sicuro in quanto restituirà un oggetto qualunque cosa:
public static class EnumEx
{
static public bool TryConvert<T>(int value, out T result)
{
result = default(T);
bool success = Enum.IsDefined(typeof(T), value);
if (success)
{
result = (T)Enum.ToObject(typeof(T), value);
}
return success;
}
}
Se sei pronto per .NET Framework 4.0 , c'è una nuova funzione Enum.TryParse () che è molto utile e gioca bene con l'attributo [Flags]. Vedi il metodo Enum.TryParse (String, TEnum%)
Se si dispone di un numero intero che funge da maschera di bit e potrebbe rappresentare uno o più valori in un elenco [Flags], è possibile utilizzare questo codice per analizzare i singoli valori di flag in un elenco:
for (var flagIterator = 0; flagIterator < 32; flagIterator++)
{
// Determine the bit value (1,2,4,...,Int32.MinValue)
int bitValue = 1 << flagIterator;
// Check to see if the current flag exists in the bit mask
if ((intValue & bitValue) != 0)
{
// If the current flag exists in the enumeration, then we can add that value to the list
// if the enumeration has that flag defined
if (Enum.IsDefined(typeof(MyEnum), bitValue))
Console.WriteLine((MyEnum)bitValue);
}
}
Si noti che ciò presuppone che il tipo sottostante di enum
sia un numero intero a 32 bit con segno. Se fosse un diverso tipo numerico, dovresti cambiare i 32 hardcoded per riflettere i bit in quel tipo (o derivarlo programmaticamente usando Enum.GetUnderlyingType()
)
Questo è un metodo di conversione sicuro consapevole dell'enumerazione di flag:
public static bool TryConvertToEnum<T>(this int instance, out T result)
where T: Enum
{
var enumType = typeof (T);
var success = Enum.IsDefined(enumType, instance);
if (success)
{
result = (T)Enum.ToObject(enumType, instance);
}
else
{
result = default(T);
}
return success;
}
Enum
invece di struct
, il che significa che non dobbiamo fare affidamento sul controllo di runtime!
Per convertire una stringa in ENUM o int in costante ENUM dobbiamo usare la funzione Enum.Parse. Ecco un video di YouTube https://www.youtube.com/watch?v=4nhx4VwdRDk che in realtà dimostra di avere una stringa e lo stesso vale per int.
Il codice va come mostrato sotto dove "rosso" è la stringa e "MyColors" è il colore ENUM che ha le costanti di colore.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Allontanandosi leggermente dalla domanda originale, ma ho trovato utile una risposta alla domanda Stack Overflow Ottieni valore int da enum . Crea una classe statica con public const int
proprietà, che ti consenta di raccogliere facilmente un insieme di int
costanti correlate e di non doverle lanciare int
quando le usi.
public static class Question
{
public static readonly int Role = 2;
public static readonly int ProjectFunding = 3;
public static readonly int TotalEmployee = 4;
public static readonly int NumberOfServers = 5;
public static readonly int TopBusinessConcern = 6;
}
Ovviamente, alcune funzionalità del tipo enum andranno perse, ma per l'archiviazione di un gruppo di costanti ID database, sembra una soluzione piuttosto ordinata.
Questo analizza numeri interi o stringhe in un enum target con una corrispondenza parziale in dot.NET 4.0 usando generici come nella classe di utilità Tawani sopra. Lo sto usando per convertire le variabili di switch della riga di comando che possono essere incomplete. Poiché un enum non può essere nullo, è necessario fornire logicamente un valore predefinito. Può essere chiamato così:
var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);
Ecco il codice:
using System;
public class EnumParser<T> where T : struct
{
public static T Parse(int toParse, T defaultVal)
{
return Parse(toParse + "", defaultVal);
}
public static T Parse(string toParse, T defaultVal)
{
T enumVal = defaultVal;
if (defaultVal is Enum && !String.IsNullOrEmpty(toParse))
{
int index;
if (int.TryParse(toParse, out index))
{
Enum.TryParse(index + "", out enumVal);
}
else
{
if (!Enum.TryParse<T>(toParse + "", true, out enumVal))
{
MatchPartialName(toParse, ref enumVal);
}
}
}
return enumVal;
}
public static void MatchPartialName(string toParse, ref T enumVal)
{
foreach (string member in enumVal.GetType().GetEnumNames())
{
if (member.ToLower().Contains(toParse.ToLower()))
{
if (Enum.TryParse<T>(member + "", out enumVal))
{
break;
}
}
}
}
}
Cordiali saluti: La domanda era sugli interi, che nessuno menzionato convertirà esplicitamente anche in Enum.TryParse ()
Da una stringa: (Enum.Parse non è aggiornato, usa Enum.TryParse)
enum Importance
{}
Importance importance;
if (Enum.TryParse(value, out importance))
{
}
Di seguito è un metodo di estensione leggermente migliore
public static string ToEnumString<TEnum>(this int enumValue)
{
var enumString = enumValue.ToString();
if (Enum.IsDefined(typeof(TEnum), enumValue))
{
enumString = ((TEnum) Enum.ToObject(typeof (TEnum), enumValue)).ToString();
}
return enumString;
}
Nel mio caso, avevo bisogno di restituire l'enum da un servizio WCF. Avevo anche bisogno di un nome descrittivo, non solo di enum.ToString ().
Ecco la mia classe WCF.
[DataContract]
public class EnumMember
{
[DataMember]
public string Description { get; set; }
[DataMember]
public int Value { get; set; }
public static List<EnumMember> ConvertToList<T>()
{
Type type = typeof(T);
if (!type.IsEnum)
{
throw new ArgumentException("T must be of type enumeration.");
}
var members = new List<EnumMember>();
foreach (string item in System.Enum.GetNames(type))
{
var enumType = System.Enum.Parse(type, item);
members.Add(
new EnumMember() { Description = enumType.GetDescriptionValue(), Value = ((IConvertible)enumType).ToInt32(null) });
}
return members;
}
}
Ecco il metodo di estensione che ottiene la descrizione dall'enum.
public static string GetDescriptionValue<T>(this T source)
{
FieldInfo fileInfo = source.GetType().GetField(source.ToString());
DescriptionAttribute[] attributes = (DescriptionAttribute[])fileInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
if (attributes != null && attributes.Length > 0)
{
return attributes[0].Description;
}
else
{
return source.ToString();
}
}
Implementazione:
return EnumMember.ConvertToList<YourType>();
Non so più dove ottengo la parte di questa estensione enum, ma proviene da StackOverflow. Mi dispiace per questo! Ma ho preso questo e l'ho modificato per enumerazioni con Flags. Per gli enum con Flags ho fatto questo:
public static class Enum<T> where T : struct
{
private static readonly IEnumerable<T> All = Enum.GetValues(typeof (T)).Cast<T>();
private static readonly Dictionary<int, T> Values = All.ToDictionary(k => Convert.ToInt32(k));
public static T? CastOrNull(int value)
{
T foundValue;
if (Values.TryGetValue(value, out foundValue))
{
return foundValue;
}
// For enums with Flags-Attribut.
try
{
bool isFlag = typeof(T).GetCustomAttributes(typeof(FlagsAttribute), false).Length > 0;
if (isFlag)
{
int existingIntValue = 0;
foreach (T t in Enum.GetValues(typeof(T)))
{
if ((value & Convert.ToInt32(t)) > 0)
{
existingIntValue |= Convert.ToInt32(t);
}
}
if (existingIntValue == 0)
{
return null;
}
return (T)(Enum.Parse(typeof(T), existingIntValue.ToString(), true));
}
}
catch (Exception)
{
return null;
}
return null;
}
}
Esempio:
[Flags]
public enum PetType
{
None = 0, Dog = 1, Cat = 2, Fish = 4, Bird = 8, Reptile = 16, Other = 32
};
integer values
1=Dog;
13= Dog | Fish | Bird;
96= Other;
128= Null;
Dovresti integrare un certo tipo di rilassamento per essere più robusto.
public static T ToEnum<T>(dynamic value)
{
if (value == null)
{
// default value of an enum is the object that corresponds to
// the default value of its underlying type
// https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/default-values-table
value = Activator.CreateInstance(Enum.GetUnderlyingType(typeof(T)));
}
else if (value is string name)
{
return (T)Enum.Parse(typeof(T), name);
}
return (T)Enum.ToObject(typeof(T),
Convert.ChangeType(value, Enum.GetUnderlyingType(typeof(T))));
}
Test Case
[Flags]
public enum A : uint
{
None = 0,
X = 1 < 0,
Y = 1 < 1
}
static void Main(string[] args)
{
var value = EnumHelper.ToEnum<A>(7m);
var x = value.HasFlag(A.X); // true
var y = value.HasFlag(A.Y); // true
var value2 = EnumHelper.ToEnum<A>("X");
var value3 = EnumHelper.ToEnum<A>(null);
Console.ReadKey();
}
Diversi modi per lanciare da e verso Enum
enum orientation : byte
{
north = 1,
south = 2,
east = 3,
west = 4
}
class Program
{
static void Main(string[] args)
{
orientation myDirection = orientation.north;
Console.WriteLine(“myDirection = {0}”, myDirection); //output myDirection =north
Console.WriteLine((byte)myDirection); //output 1
string strDir = Convert.ToString(myDirection);
Console.WriteLine(strDir); //output north
string myString = “north”; //to convert string to Enum
myDirection = (orientation)Enum.Parse(typeof(orientation),myString);
}
}
Può aiutarti a convertire qualsiasi dato di input nell'enum desiderato dall'utente . Supponiamo di avere un enum come sotto che di default int . Aggiungi un valore predefinito all'inizio del tuo enum. Che viene utilizzato nel medthod degli helper quando non viene trovata alcuna corrispondenza con il valore di input.
public enum FriendType
{
Default,
Audio,
Video,
Image
}
public static class EnumHelper<T>
{
public static T ConvertToEnum(dynamic value)
{
var result = default(T);
var tempType = 0;
//see Note below
if (value != null &&
int.TryParse(value.ToString(), out tempType) &&
Enum.IsDefined(typeof(T), tempType))
{
result = (T)Enum.ToObject(typeof(T), tempType);
}
return result;
}
}
NB: Qui provo ad analizzare il valore in int, perché enum è di default int Se si definisce enum in questo modo, che è di tipo byte .
public enum MediaType : byte
{
Default,
Audio,
Video,
Image
}
È necessario modificare l'analisi dal metodo helper da
int.TryParse(value.ToString(), out tempType)
per
byte.TryParse(value.ToString(), out tempType)
Controllo il mio metodo per i seguenti input
EnumHelper<FriendType>.ConvertToEnum(null);
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("-1");
EnumHelper<FriendType>.ConvertToEnum("6");
EnumHelper<FriendType>.ConvertToEnum("");
EnumHelper<FriendType>.ConvertToEnum("2");
EnumHelper<FriendType>.ConvertToEnum(-1);
EnumHelper<FriendType>.ConvertToEnum(0);
EnumHelper<FriendType>.ConvertToEnum(1);
EnumHelper<FriendType>.ConvertToEnum(9);
mi scusi per il mio inglese
Ecco un metodo di estensione che getta Int32
a Enum
.
Rispetta i flag bit a bit anche quando il valore è superiore al massimo possibile. Per esempio se hai un enum con possibilità 1 , 2 e 4 , ma int è 9 , capisce che come 1 in assenza di un 8 . Ciò consente di effettuare aggiornamenti dei dati prima degli aggiornamenti del codice.
public static TEnum ToEnum<TEnum>(this int val) where TEnum : struct, IComparable, IFormattable, IConvertible
{
if (!typeof(TEnum).IsEnum)
{
return default(TEnum);
}
if (Enum.IsDefined(typeof(TEnum), val))
{//if a straightforward single value, return that
return (TEnum)Enum.ToObject(typeof(TEnum), val);
}
var candidates = Enum
.GetValues(typeof(TEnum))
.Cast<int>()
.ToList();
var isBitwise = candidates
.Select((n, i) => {
if (i < 2) return n == 0 || n == 1;
return n / 2 == candidates[i - 1];
})
.All(y => y);
var maxPossible = candidates.Sum();
if (
Enum.TryParse(val.ToString(), out TEnum asEnum)
&& (val <= maxPossible || !isBitwise)
){//if it can be parsed as a bitwise enum with multiple flags,
//or is not bitwise, return the result of TryParse
return asEnum;
}
//If the value is higher than all possible combinations,
//remove the high imaginary values not accounted for in the enum
var excess = Enumerable
.Range(0, 32)
.Select(n => (int)Math.Pow(2, n))
.Where(n => n <= val && n > 0 && !candidates.Contains(n))
.Sum();
return Enum.TryParse((val - excess).ToString(), out asEnum) ? asEnum : default(TEnum);
}
il modo semplice e chiaro per lanciare un int da enumerare in c #:
public class Program
{
public enum Color : int
{
Blue = 0,
Black = 1,
Green = 2,
Gray = 3,
Yellow =4
}
public static void Main(string[] args)
{
//from string
Console.WriteLine((Color) Enum.Parse(typeof(Color), "Green"));
//from int
Console.WriteLine((Color)2);
//From number you can also
Console.WriteLine((Color)Enum.ToObject(typeof(Color) ,2));
}
}
È sufficiente utilizzare la conversione esplicita Cast int per enum o enum in int
class Program
{
static void Main(string[] args)
{
Console.WriteLine((int)Number.three); //Output=3
Console.WriteLine((Number)3);// Outout three
Console.Read();
}
public enum Number
{
Zero = 0,
One = 1,
Two = 2,
three = 3
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
namespace SamplePrograme
{
public class Program
{
public enum Suit : int
{
Spades = 0,
Hearts = 1,
Clubs = 2,
Diamonds = 3
}
public static void Main(string[] args)
{
//from string
Console.WriteLine((Suit) Enum.Parse(typeof(Suit), "Clubs"));
//from int
Console.WriteLine((Suit)1);
//From number you can also
Console.WriteLine((Suit)Enum.ToObject(typeof(Suit) ,1));
}
}
}
Fai proprio come di seguito:
int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;
Per assicurarti di lanciare solo i valori giusti e che puoi generare un'eccezione altrimenti:
int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
TargetEnum target = (TargetEnum)intToCast ;
}
else
{
// Throw your exception.
}
Si noti che l'utilizzo di IsDefined è costoso e persino più del semplice casting, quindi dipende dalla propria implementazione decidere di usarlo o meno.
È possibile utilizzare il metodo di estensione.
public static class Extensions
{
public static T ToEnum<T>(this string data) where T : struct
{
if (!Enum.TryParse(data, true, out T enumVariable))
{
if (Enum.IsDefined(typeof(T), enumVariable))
{
return enumVariable;
}
}
return default;
}
public static T ToEnum<T>(this int data) where T : struct
{
return (T)Enum.ToObject(typeof(T), data);
}
}
usare come il codice qui sotto
enum:
public enum DaysOfWeeks
{
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7,
}
Utilizzo:
string Monday = "Mon";
int Wednesday = 3;
var Mon = Monday.ToEnum<DaysOfWeeks>();
var Wed = Wednesday.ToEnum<DaysOfWeeks>();
YourEnum
è dinamico e sarà noto solo in fase di esecuzione, e quello che voglio è convertire inEnum
?