Yanıtlar:
Bir dizeden:
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.")
}
Bir int'den:
YourEnum foo = (YourEnum)yourInt;
Güncelleme:
Numaradan da yapabilirsiniz
YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);
var result = Enum.TryParse(yourString, out yourEnum)
bugünlerde gerçekten kullanmalısınız (ve dönüşümün başarısız olup olmadığını belirlemek için sonucu kontrol etmelisiniz ).
Enum.Parse
bir true
parametre değeri ekleyerek büyük / küçük harfe duyarsız olmak da mümkündür :YourEnum foo = (YourEnum) Enum.Parse(typeof(YourEnum), yourString, true);
Sadece yayınla:
MyEnum e = (MyEnum)3;
Menzil içinde olup olmadığını Enum.IsDefined kullanarak kontrol edebilirsiniz :
if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }
Enum.IsDefined
, bu tehlikeli olabilir unutmayın: msdn.microsoft.com/en-us/library/ms229025(VS.90).aspx
IsDefined
giriş değerlerini kontrol etmek, bir geçerdi sonra yeni enum değerler ekleyerek insanlara karşı savunmasız kendinizi bırakın IsDefined
yeni beri çek ( değeri yeni kodda bulunur), ancak yazdığınız orijinal kodla çalışmayabilir. Bu nedenle, kodunuzun işleyebileceği enum değerlerini açıkça belirtmek daha güvenlidir.
Alternatif olarak, bir astar yerine bir uzantı yöntemi kullanın:
public static T ToEnum<T>(this string enumString)
{
return (T) Enum.Parse(typeof (T), enumString);
}
Kullanımı:
Color colorEnum = "Red".ToEnum<Color>();
VEYA
string color = "Red";
var colorEnum = color.ToEnum<Color>();
System.String
ad alanı kirliliği gibi görünüyor
Ben tam bir cevap almak düşünüyorum, insanlar enum .NET içinde dahili olarak nasıl çalıştığını bilmek zorunda.
Şeyler nasıl çalışır
.NET'teki bir numaralandırma, bir değer kümesini (alanları) temel bir türe (varsayılan değer int
) eşleyen bir yapıdır . Ancak, enum'unuzun eşlediği integral türünü gerçekten seçebilirsiniz:
public enum Foo : short
Bu durumda, numaralandırma short
veri türüyle eşleştirilir , yani bellekte kısa olarak saklanacak ve yayınladığınızda ve kullandığınızda kısa olarak davranacaktır.
Bir IL açısından bakarsanız, (normal, int) bir enum şöyle görünür:
.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__
}
Burada dikkatinizi çeken şey value__
, enum değerlerinden ayrı olarak saklanmasıdır. Foo
Yukarıdaki numaralandırma durumunda , türü value__
int16'dır. Bu, temel olarak, türler eşleştiği sürece , bir numarada istediğiniz her şeyi depolayabileceğiniz anlamına gelir .
Bu noktada System.Enum
, bir değer türü olduğunu belirtmek isterim , bu temelde BarFlag
bellekte 4 bayt Foo
alacak ve 2 alacak - örneğin altta yatan türün boyutu (aslında bundan daha karmaşıktır, ancak Hey...).
Cevap
Bu nedenle, bir numaralandırmaya eşlemek istediğiniz bir tamsayı varsa, çalışma zamanının yalnızca 2 şey yapması gerekir: 4 baytı kopyalayın ve başka bir ad verin (numaralandırmanın adı). Veriler değer türü olarak saklandığından kopyalama örtüktür - bu, temel olarak yönetilmeyen kod kullanırsanız, enum ve tam sayıları veri kopyalamadan değiştirebileceğiniz anlamına gelir.
Güvenli hale getirmek için , altta yatan türlerin aynı veya dolaylı olarak dönüştürülebilir olduğunu bilmek ve enum değerlerinin var olmasını sağlamak için en iyi uygulama olduğunu düşünüyorum (varsayılan olarak kontrol edilmez!).
Bunun nasıl çalıştığını görmek için aşağıdaki kodu deneyin:
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();
}
Dökümün e2
de işe yaradığını unutmayın! Bu markaları anlamda yukarıdaki derleyici açısından bakıldığında: value__
Alan basitçe ya 5 ya da 6 ve dolu Console.WriteLine
aramaların ToString()
, adı e1
ismi olurken çözülene e2
değildir.
İstediğiniz bu değilse, kullandığınız Enum.IsDefined(typeof(MyEnum), 6)
değerin tanımlı bir numaraya eşlenip eşlenmediğini kontrol etmek için kullanın .
Derleyici aslında bu kontrol olsa da, enum altta yatan türü hakkında açık olduğumu unutmayın. Bunu, yolda sürprizlerle karşılaşmamam için yapıyorum. Bu sürprizleri görmek için aşağıdaki kodu kullanabilirsiniz (aslında bunun veritabanı kodunda çok olduğunu gördüm):
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
, Fırlatacak (kutudan çıkarma başarısız). Eğer yaparsanız object o = (short)5;
, işe yarayacak, çünkü o zaman türler eşleşecek. Menzil hakkında değil, gerçekten tür hakkında.
Aşağıdaki örneği alın:
int one = 1;
MyEnum e = (MyEnum)one;
Bu kod parçasını benim numaralandırma int döküm için kullanıyorum:
if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }
Bunu en iyi çözüm olarak görüyorum.
Aşağıda Enums için güzel bir yardımcı program sınıfı
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;
}
}
Sayısal değerler için, ne olursa olsun bir nesneyi döndüreceği için bu daha güvenlidir:
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;
}
}
4.0 .NET Framework için hazırsanız , çok kullanışlı olan ve [Flags] özniteliğiyle iyi çalışan yeni bir Enum.TryParse () işlevi vardır. Bkz. Enum.TryParse Yöntemi (Dize,% TEnum)
Bit maskesi olarak işlev gören ve [Bayraklar] numaralamasında bir veya daha fazla değeri temsil edebilecek bir tamsayı varsa, tek tek bayrak değerlerini bir listede ayrıştırmak için bu kodu kullanabilirsiniz:
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);
}
}
Bunun altında yatan türün enum
işaretli bir 32 bit tam sayı olduğunu varsayarız . Farklı bir sayısal tür olsaydı, kodlanmış 32'yi bu türdeki bitleri yansıtacak şekilde değiştirmelisiniz (veya bunu kullanarak programlı olarak türetmelisiniz Enum.GetUnderlyingType()
)
Bu bir bayrak numaralandırma farkında güvenli dönüştürme yöntemi:
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
bunun yerine C # 7.3 ile geliştirilebilir struct
, yani çalışma zamanı kontrolüne güvenmemiz gerekmez!
Bir dizeyi ENUM veya int yerine ENUM sabitine dönüştürmek için Enum.Parse işlevini kullanmamız gerekir. İşte bir youtube video https://www.youtube.com/watch?v=4nhx4VwdRDk aslında dize ile gösterir ve aynı int için geçerlidir.
Kod aşağıda gösterildiği gibi gider, burada "kırmızı" dizgidir ve "MyColors" renk sabitlerine sahip ENUM rengidir.
MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");
Biraz uzakta asıl soruya aldığım ama bulundu yığın taşması soru bir cevap enum Al int değeri yararlıdır. public const int
İlgili int
sabitleri bir araya getirmenize ve ardından bunları int
kullanırken bunları kullanmanıza gerek kalmadan özelliklere sahip statik bir sınıf oluşturun .
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;
}
Açıkçası, enum tipi işlevlerinden bazıları kaybolacak, ancak bir dizi veritabanı kimliği sabitini saklamak için oldukça düzenli bir çözüm gibi görünüyor.
Bu, yukarıdaki Tawani yardımcı program sınıfındaki gibi jenerikler kullanarak dot.NET 4.0'da kısmi eşleme ile tamsayıları veya dizeleri bir hedef numaraya ayrıştırır. Ben eksik olabilir komut satırı anahtarı değişkenleri dönüştürmek için kullanıyorum. Bir numaralandırma boş olamayacağından, mantıksal olarak varsayılan bir değer sağlamalısınız. Bu şekilde çağrılabilir:
var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);
İşte kod:
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: Soru, söz konusu hiç kimsenin Enum.TryParse () içinde de açıkça dönüşmeyeceği tamsayılarla ilgiliydi.
Bir dizeden: (Enum.Parse güncel değil, Enum.TryParse öğesini kullanın)
enum Importance
{}
Importance importance;
if (Enum.TryParse(value, out importance))
{
}
Aşağıdaki biraz daha iyi genişletme yöntemidir
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;
}
Benim durumumda, bir WCF hizmetinden numaralandırma dönmek gerekiyordu. Ayrıca sadece enum.ToString () değil, kolay bir isme ihtiyacım vardı.
İşte benim WCF Sınıfım.
[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;
}
}
İşte Enum'dan Açıklama alan Extension yöntemi.
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();
}
}
Uygulama:
return EnumMember.ConvertToList<YourType>();
Artık bu numaralandırma uzantısının bir parçasını nereden aldığımı bilmiyorum, ancak stackoverflow'dan. Bunun için üzgünüm! Ama bunu aldım ve Bayraklı numaralandırmalar için değiştirdim. Bayraklı numaralandırmalar için bunu yaptım:
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;
}
}
Misal:
[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;
Daha sağlam olmak için bir tür eşleştirme gevşemesi yapmalısınız.
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 durumu
[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();
}
Döküm için farklı yolları ve gelen 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);
}
}
Herhangi bir giriş verisini kullanıcının istediği numaraya dönüştürmenize yardımcı olabilir . Diyelim ki varsayılan olarak int . Lütfen numaralandırmanızın başına bir Varsayılan değer ekleyin . Girdi değeri ile eşleşme bulunmadığında yardımcılarda kullanılır.
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;
}
}
Not: Burada enum varsayılan olarak int çünkü değer içine ayrıştırmak çalışıyorum Eğer bayt türü olan bu gibi numaralandırma tanımlarsanız .
public enum MediaType : byte
{
Default,
Audio,
Video,
Image
}
Yardımcı yöntemde ayrışmayı şu yöntemle değiştirmeniz gerekir:
int.TryParse(value.ToString(), out tempType)
için
byte.TryParse(value.ToString(), out tempType)
Aşağıdaki girişler için yöntemimi kontrol ediyorum
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);
İngilizcem için üzgünüm
İşte atmalarını bir uzantısı yöntemidir Int32
için Enum
.
Değer mümkün olan en yüksek değerden daha yüksek olsa bile bitsel bayrakları onurlandırır. Örneğin , 1 , 2 ve 4 olasılıkları olan bir enumunuz varsa , ancak int 9 ise , 8'in yokluğunda 1 olarak anlar . Bu, kod güncellemelerinden önce veri güncellemeleri yapmanızı sağlar.
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);
}
c # numaralandırma bir int döküm için kolay ve net yolu:
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));
}
}
Sadece intum enum için açık dönüşüm Cast veya int enum
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));
}
}
}
Sadece aşağıdaki gibi yapın:
int intToCast = 1;
TargetEnum f = (TargetEnum) intToCast ;
Yalnızca doğru değerleri verdiğinizden ve bunun dışında bir istisna atabildiğinizden emin olmak için:
int intToCast = 1;
if (Enum.IsDefined(typeof(TargetEnum), intToCast ))
{
TargetEnum target = (TargetEnum)intToCast ;
}
else
{
// Throw your exception.
}
IsDefined'i kullanmanın maliyetli ve hatta dökümden daha fazlası olduğunu unutmayın, bu yüzden onu kullanmaya karar vermeniz uygulamanıza bağlıdır.
Uzantı yöntemini kullanabilirsiniz.
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);
}
}
feryat kodu gibi kullan
Sıralama :
public enum DaysOfWeeks
{
Monday = 1,
Tuesday = 2,
Wednesday = 3,
Thursday = 4,
Friday = 5,
Saturday = 6,
Sunday = 7,
}
Kullanımı:
string Monday = "Mon";
int Wednesday = 3;
var Mon = Monday.ToEnum<DaysOfWeeks>();
var Wed = Wednesday.ToEnum<DaysOfWeeks>();
YourEnum
ve yalnızca çalışma zamanında bilinecekse ve dönüştürmek istediğim şeyEnum
nedir?