Jawaban:
Dari sebuah string:
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.")
}
Dari int:
YourEnum foo = (YourEnum)yourInt;
Memperbarui:
Dari nomor Anda juga bisa
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
var result = Enum.TryParse(yourString, out yourEnum)
saat ini (dan memeriksa hasilnya untuk menentukan apakah konversi gagal).
Enum.Parse
menjadi case-insensitive dengan menambahkan true
nilai parameter pada panggilan:YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
Hanya melemparkannya:
MyEnum e = (MyEnum)3;
Anda dapat memeriksa apakah jangkauannya menggunakan Enum.IsDefined :
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Enum.IsDefined
, ketahuilah bahwa itu bisa berbahaya: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
IsDefined
untuk memeriksa nilai input, Anda membuat diri Anda rentan terhadap orang menambahkan nilai enum baru nanti yang akan melewati IsDefined
pemeriksaan (karena baru nilai ada dalam kode baru), tetapi mungkin tidak berfungsi dengan kode asli yang Anda tulis. Oleh karena itu lebih aman untuk secara eksplisit menentukan nilai enum yang dapat ditangani oleh kode Anda.
Atau, gunakan metode ekstensi alih-alih satu baris:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
Pemakaian:
Color colorEnum = "Red".ToEnum<Color>();
ATAU
string color = "Red";
var colorEnum = color.ToEnum<Color>();
System.String
sepertinya seperti polusi namespace
Saya pikir untuk mendapatkan jawaban yang lengkap, orang harus tahu bagaimana enum bekerja secara internal di .NET.
Bagaimana cara kerjanya?
Enum di .NET adalah struktur yang memetakan serangkaian nilai (bidang) ke tipe dasar (defaultnya adalah int
). Namun, Anda sebenarnya dapat memilih tipe integral yang dipetakan oleh enum Anda:
public enum Foo : short
Dalam hal ini enum dipetakan ke short
tipe data, yang berarti enum akan disimpan dalam memori sebagai pendek dan akan berperilaku sebagai pendek ketika Anda menggunakan dan menggunakannya.
Jika Anda melihatnya dari sudut pandang IL, enum (normal, int) terlihat seperti ini:
.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__
}
Apa yang harus mendapat perhatian Anda di sini adalah bahwa value__
disimpan secara terpisah dari nilai enum. Dalam kasus enum di Foo
atas, tipe value__
int16. Ini pada dasarnya berarti bahwa Anda dapat menyimpan apa pun yang Anda inginkan dalam enum, selama jenisnya cocok .
Pada titik ini saya ingin menunjukkan bahwa itu System.Enum
adalah tipe nilai, yang pada dasarnya berarti BarFlag
akan memakan 4 byte dalam memori dan Foo
akan memakan 2 - misalnya ukuran tipe yang mendasarinya (sebenarnya lebih rumit dari itu, tetapi Hei...).
Jawabannya
Jadi, jika Anda memiliki bilangan bulat yang ingin Anda petakan ke enum, runtime hanya perlu melakukan 2 hal: salin 4 byte dan beri nama yang lain (nama enum). Menyalin adalah implisit karena data disimpan sebagai tipe nilai - ini pada dasarnya berarti bahwa jika Anda menggunakan kode yang tidak dikelola, Anda dapat dengan mudah bertukar enum dan bilangan bulat tanpa menyalin data.
Untuk membuatnya aman, saya pikir itu praktik terbaik untuk mengetahui bahwa tipe yang mendasarinya adalah sama atau secara implisit dapat dikonversi dan untuk memastikan nilai enum ada (mereka tidak diperiksa secara default!).
Untuk melihat cara kerjanya, coba kode berikut:
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();
}
Perhatikan bahwa casting e2
juga berfungsi! Dari perspektif kompiler di atas ini masuk akal: value__
bidang hanya diisi dengan 5 atau 6 dan ketika Console.WriteLine
panggilan ToString()
, nama e1
diselesaikan sementara nama e2
tidak.
Jika bukan itu yang Anda maksudkan, gunakan Enum.IsDefined(typeof(MyEnum), 6)
untuk memeriksa apakah nilai yang Anda lemparkan peta ke enum yang ditentukan.
Perhatikan juga bahwa saya eksplisit tentang tipe enum yang mendasarinya, meskipun kompiler benar-benar memeriksa ini. Saya melakukan ini untuk memastikan saya tidak mengalami kejutan di jalan. Untuk melihat kejutan ini dalam tindakan, Anda dapat menggunakan kode berikut (sebenarnya saya sering melihat ini terjadi dalam kode basis data):
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
, Ia akan melempar (pembatalan kotak gagal). Jika Anda melakukannya object o = (short)5;
, itu akan berhasil, karena jenisnya akan cocok. Ini bukan tentang kisaran, ini tentang jenis.
Ambil contoh berikut:
int one = 1;
MyEnum e = (MyEnum)one;
Saya menggunakan potongan kode ini untuk memberikan int ke enum saya:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
Saya menemukannya solusi terbaik.
Di bawah ini adalah kelas utilitas yang bagus untuk 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;
}
}
Untuk nilai numerik, ini lebih aman karena akan mengembalikan objek apa pun yang terjadi:
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;
}
}
Jika Anda siap untuk 4.0 .NET Framework, ada fungsi Enum.TryParse () baru yang sangat berguna dan berfungsi dengan baik dengan atribut [Flags]. Lihat Metode Enum.TryParse (String, TEnum%)
Jika Anda memiliki integer yang bertindak sebagai bitmask dan bisa mewakili satu atau lebih nilai dalam enumerasi [Bendera], Anda bisa menggunakan kode ini untuk mem-parsing nilai flag individual ke dalam daftar:
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);
}
}
Perhatikan bahwa ini mengasumsikan bahwa tipe yang mendasari enum
adalah integer 32-bit yang ditandatangani. Jika itu adalah tipe numerik yang berbeda, Anda harus mengubah hardcoded 32 untuk mencerminkan bit dalam tipe itu (atau secara terprogram menurunkannya menggunakan Enum.GetUnderlyingType()
)
Ini adalah metode pengubahan tanda sadar konversi bendera:
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
alih-alih struct
, artinya kita tidak harus bergantung pada pemeriksaan runtime!
Untuk mengonversi string menjadi ENUM atau int menjadi ENUM, kita perlu menggunakan fungsi Enum.Parse. Ini adalah video youtube https://www.youtube.com/watch?v=4nhx4VwdRDk yang sebenarnya menunjukkan dengan string dan hal yang sama berlaku untuk int.
Kode berjalan seperti yang ditunjukkan di bawah ini di mana "merah" adalah string dan "MyColors" adalah warna ENUM yang memiliki konstanta warna.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Sedikit menjauh dari pertanyaan awal, tetapi saya menemukan jawaban untuk pertanyaan Stack Overflow Dapatkan nilai int dari enum berguna. Buat kelas statis dengan public const int
properti, yang memungkinkan Anda untuk dengan mudah mengumpulkan sekelompok int
konstanta terkait , dan kemudian tidak harus membuangnya int
saat menggunakannya.
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;
}
Jelas, beberapa fungsionalitas tipe enum akan hilang, tetapi untuk menyimpan sekelompok konstanta id database, sepertinya solusi yang cukup rapi.
Ini mem-parsing bilangan bulat atau string ke target enum dengan pencocokan parsial di dot.NET 4.0 menggunakan obat generik seperti pada kelas utilitas Tawani di atas. Saya menggunakannya untuk mengubah variabel saklar baris perintah yang mungkin tidak lengkap. Karena enum tidak boleh nol, Anda harus memberikan nilai default secara logis. Ini bisa disebut seperti ini:
var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);
Berikut kodenya:
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;
}
}
}
}
}
FYI: Pertanyaannya adalah tentang bilangan bulat, yang tidak ada yang disebutkan juga akan secara eksplisit dikonversi di Enum.TryParse ()
Dari string: (Enum.Parse kedaluwarsa, gunakan Enum.TryParse)
enum Importance
{}
Importance importance;
if (Enum.TryParse(value, out importance))
{
}
Berikut ini adalah metode ekstensi yang sedikit lebih baik
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;
}
Dalam kasus saya, saya perlu mengembalikan enum dari layanan WCF. Saya juga membutuhkan nama yang ramah, bukan hanya enum.ToString ().
Inilah Kelas WCF saya.
[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;
}
}
Inilah metode Extension yang mendapatkan Deskripsi dari 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();
}
}
Penerapan:
return EnumMember.ConvertToList<YourType>();
Saya tidak tahu lagi dari mana saya mendapatkan bagian dari ekstensi enum ini, tetapi dari stackoverflow. Saya minta maaf untuk ini! Tetapi saya mengambil yang ini dan memodifikasinya untuk enum dengan Bendera. Untuk enum dengan Bendera saya melakukan ini:
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;
}
}
Contoh:
[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;
Anda harus membangun beberapa jenis relaksasi yang cocok agar lebih kuat.
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))));
}
Kasus cobaan
[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();
}
Berbagai cara dilemparkan ke dan dari 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);
}
}
Ini dapat membantu Anda mengonversi data input apa pun ke enum yang diinginkan pengguna . Misalkan Anda memiliki enum seperti di bawah ini yang secara default int . Harap tambahkan nilai Default di awal enum Anda. Yang digunakan pada medthod helper ketika tidak ditemukan kecocokan dengan nilai 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: Di sini saya mencoba mem-parsing nilai ke int, karena enum secara default int Jika Anda mendefinisikan enum seperti ini yang merupakan tipe byte .
public enum MediaType : byte
{
Default,
Audio,
Video,
Image
}
Anda perlu mengubah metode parsing at helper dari
int.TryParse(value.ToString(), out tempType)
untuk
byte.TryParse(value.ToString(), out tempType)
Saya memeriksa metode saya untuk input berikut
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);
maaf untuk bahasa inggris saya
Inilah metode ekstensi yang digunakan Int32
untuk Enum
.
Itu menghormati bendera bitwise bahkan ketika nilainya lebih tinggi dari maksimum yang mungkin. Misalnya jika Anda memiliki enum dengan kemungkinan 1 , 2 , dan 4 , tetapi intnya adalah 9 , ia memahami bahwa sebagai 1 tanpa adanya 8 . Ini memungkinkan Anda melakukan pembaruan data sebelum pembaruan kode.
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);
}
cara mudah dan jelas untuk menampilkan int ke enum di 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));
}
}
Anda cukup menggunakan Konversi konversi Cast int ke enum atau enum ke 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));
}
}
}
Anda cukup melakukan seperti di bawah ini:
int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;
Untuk memastikan bahwa Anda hanya memberikan nilai yang benar dan Anda dapat melemparkan pengecualian:
int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
TargetEnum target = (TargetEnum)intToCast ;
}
else
{
// Throw your exception.
}
Perhatikan bahwa menggunakan IsDefined mahal dan bahkan lebih dari sekadar casting, jadi itu tergantung pada implementasi Anda untuk memutuskan untuk menggunakannya atau tidak.
Anda dapat menggunakan metode ekstensi.
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);
}
}
gunakan kode seperti di bawah ini
enum:
public enum DaysOfWeeks
{
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7,
}
Penggunaan:
string Monday = "Mon";
int Wednesday = 3;
var Mon = Monday.ToEnum<DaysOfWeeks>();
var Wed = Wednesday.ToEnum<DaysOfWeeks>();
YourEnum
dinamis dan hanya akan diketahui saat runtime, dan apa yang saya inginkan adalah konversiEnum
?