Bagaimana bisa sebuah int
akan dilemparkan ke sebuah enum
di C#?
Dari 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;
Update:
Dari jumlah anda juga bisa
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
Hanya cor itu:
MyEnum e = (MyEnum)3;
Anda dapat memeriksa apakah itu's dalam kisaran yang menggunakan Enum.IsDefined:
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Atau, menggunakan metode penyuluhan bukan satu-liner:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
Penggunaan:
Color colorEnum = "Red".ToEnum<Color>();
ATAU
string color = "Red";
var colorEnum = color.ToEnum<Color>();
Saya berpikir untuk mendapatkan jawaban yang lengkap, orang-orang harus tahu bagaimana enums bekerja secara internal dalam .NET.
Bagaimana hal-hal bekerja
Enum dalam .NET adalah sebuah struktur yang memetakan satu set nilai-nilai (bidang) untuk jenis dasar (default adalah int
). Namun, sebenarnya anda bisa memilih tipe integral yang anda enum peta:
public enum Foo : short
Dalam hal ini enum dipetakan ke pendek
tipe data, yang berarti itu akan disimpan dalam memori jangka pendek dan akan berperilaku seperti yang singkat, ketika anda melemparkan dan menggunakannya.
Jika anda melihat dari IL point of view, a (normal, int) enum 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 mendapatkan perhatian di sini adalah bahwa nilai ' __
disimpan secara terpisah dari nilai-nilai enum. Dalam kasus enum Foo
di atas, jenis nilai __
adalah int16. Ini pada dasarnya berarti bahwa anda dapat menyimpan apapun yang anda inginkan dalam sebuah enum, asalkan jenis pertandingan.
Pada titik ini saya'd ingin menunjukkan bahwa Sistem.Enum
adalah jenis nilai, yang pada dasarnya berarti bahwa BarFlag
akan mengambil 4 byte dalam memori dan Foo
akan mengambil 2 -- misalnya ukuran yang mendasari tipe (it's benar-benar lebih rumit dari itu, tapi hei...).
Jawaban
Jadi, jika anda memiliki sebuah integer yang anda ingin peta untuk enum, runtime hanya perlu melakukan 2 hal: copy 4 byte dan nama itu sesuatu yang lain (nama enum). Penyalinan implisit karena data yang disimpan seperti tipe nilai - ini pada dasarnya berarti bahwa jika anda menggunakan kode yang tidak dikelola, anda hanya dapat interchange enums dan bulat tanpa menyalin data.
Untuk membuatnya aman, saya pikir itu's best practice untuk tahu bahwa yang mendasari jenis yang sama atau secara implisit convertible dan untuk memastikan enum nilai-nilai yang ada (mereka tidak't dicentang secara default!).
Untuk melihat bagaimana ini bekerja, cobalah 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 untuk e2
juga bekerja! Dari compiler perspektif di atas ini masuk akal: nilai ' __
field ini hanya diisi dengan baik 5 atau 6 dan ketika Konsol.WriteLine
panggilan ToString()
, nama e1
diselesaikan sedangkan nama e2
tidak.
Jika itu's tidak apa yang anda inginkan, gunakan Enum.IsDefined(typeof(MyEnum), 6)
untuk memeriksa jika nilai anda adalah casting maps untuk didefinisikan enum.
Juga perhatikan bahwa I'm eksplisit tentang yang mendasari tipe enum, meskipun compiler sebenarnya pemeriksaan ini. I'm melakukan hal ini untuk memastikan saya don't berjalan ke setiap kejutan di jalan. Untuk melihat kejutan ini dalam tindakan, anda dapat menggunakan kode berikut (sebenarnya saya've melihat ini terjadi banyak di database kode):
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();
}
Ambil contoh berikut:
int one = 1;
MyEnum e = (MyEnum)one;
Di bawah ini adalah sebuah utilitas yang bagus untuk kelas 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-nilai numerik, ini lebih aman karena akan mengembalikan sebuah objek tidak peduli apa:
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're-siap untuk 4.0 .NET Kerangka, ada's baru Enum.TryParse() fungsi yang's sangat berguna dan bermain baik dengan [Flag] atribut. Melihat Enum.TryParse
Jika anda memiliki sebuah integer yang bertindak sebagai bitmask dan bisa mewakili satu atau lebih nilai-nilai dalam [Flag] pencacahan, anda dapat menggunakan kode ini untuk mengurai individu bendera nilai-nilai ke 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);
}
}
Catatan bahwa ini mengasumsikan bahwa yang mendasari jenis enum
adalah signed 32-bit integer. Jika itu adalah numerik yang berbeda jenis, anda'd harus mengubah hardcoded 32 untuk mencerminkan bit dalam jenis (atau secara programatik diturunkan menggunakan Enum.GetUnderlyingType()
)
Ini adalah sebuah bendera pencacahan menyadari aman mengkonversi metode:
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;
}
Untuk mengkonversi string ke ENUM atau int ENUM konstan kita perlu menggunakan Enum.Mengurai fungsi. Berikut ini adalah video youtube [
yang benar-benar menunjukkan's dengan string dan yang sama berlaku untuk int.Kode berjalan seperti yang ditunjukkan di bawah ini di mana "red" adalah string dan "MyColors" adalah warna ENUM yang memiliki warna konstanta.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Sedikit menjauh dari pertanyaan awal, tapi saya menemukan jawaban Stack Overflow pertanyaan Dapatkan int nilai dari enum yang berguna. Membuat kelas statis dengan public const int
properties, yang memungkinkan anda untuk dengan mudah mengumpulkan bersama-sama sekelompok yang terkait dengan int
konstanta, dan kemudian tidak harus membuang mereka ke int
ketika menggunakan mereka.
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 dari tipe enum fungsi akan hilang, tapi untuk menyimpan sekumpulan database id konstanta, sepertinya cukup rapi solusi.
Ini mem-parsing integer atau string untuk target enum dengan pencocokan sebagian di dot.NET 4.0 menggunakan obat generik seperti di Tawani's utilitas kelas atas. Saya menggunakannya untuk mengkonversi switch baris perintah variabel yang mungkin tidak lengkap. Sejak enum tidak boleh null, anda harus logis memberikan nilai default. Hal ini dapat disebut seperti ini:
var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);
Berikut ini's kode:
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 tak seorang pun disebutkan akan juga secara eksplisit mengkonversi Enum.TryParse()
Berikut ini adalah sedikit lebih baik metode penyuluhan
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 untuk kembali enum dari layanan WCF. Saya juga butuh nama, bukan hanya enum.ToString().
Berikut ini's my WCF Kelas.
[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;
}
}
Berikut ini's metode Penyuluhan yang mendapat Keterangan 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();
}
}
Pelaksanaan:
return EnumMember.ConvertToList<YourType>();
Cara yang berbeda untuk cor dan 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);
}
}
Saya don't tahu di mana lagi aku mendapatkan bagian dari enum ekstensi, tapi itu adalah dari stackoverflow. Saya minta maaf untuk ini! Tapi aku butuh yang satu ini dan dimodifikasi untuk enums dengan Bendera. Untuk enums dengan Bendera yang saya lakukan 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;