كيف يمكنك تعداد enum
في C #؟
مثلا لا يتم ترجمة التعليمات البرمجية التالية:
public enum Suit
{
Spades,
Hearts,
Clubs,
Diamonds
}
public void EnumerateAllSuitsDemoMethod()
{
foreach (Suit suit in Suit)
{
DoSomething(suit);
}
}
ويعطي الخطأ وقت الترجمة التالي:
"البدلة" عبارة عن "نوع" ولكنها تُستخدم كـ "متغير"
فشل في الكلمة الأساسية Suit
، الثانية.
foreach (Suit suit in (Suit[]) Enum.GetValues(typeof(Suit)))
{
}
ملاحظة : المدلى بها إلى (Suit[])
ليست ضرورية للغاية ، لكنها تجعل الكود 0.5 نانومتر أسرع.
يبدو لي أنك تريد حقًا طباعة أسماء كل تعداد ، بدلاً من القيم. في هذه الحالة ، يبدو أن الدالة Enum.GetNames()
هي الطريقة الصحيحة.
public enum Suits
{
Spades,
Hearts,
Clubs,
Diamonds,
NumSuits
}
public void PrintAllSuits()
{
foreach (string name in Enum.GetNames(typeof(Suits)))
{
System.Console.WriteLine(name);
}
}
بالمناسبة ، زيادة القيمة ليست طريقة جيدة لتعداد قيم التعداد. يجب عليك القيام بذلك بدلا من ذلك.
أود استخدام Enum.GetValues(typeof(Suit))
بدلاً من ذلك.
public enum Suits
{
Spades,
Hearts,
Clubs,
Diamonds,
NumSuits
}
public void PrintAllSuits()
{
foreach (var suit in Enum.GetValues(typeof(Suits)))
{
System.Console.WriteLine(suit.ToString());
}
}
قمت ببعض الإضافات لسهولة استخدام التعداد ، ربما يمكن لأي شخص استخدامها ...
public static class EnumExtensions
{
/// <summary>
/// Gets all items for an enum value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">The value.</param>
/// <returns></returns>
public static IEnumerable<T> GetAllItems<T>(this Enum value)
{
foreach (object item in Enum.GetValues(typeof(T)))
{
yield return (T)item;
}
}
/// <summary>
/// Gets all items for an enum type.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">The value.</param>
/// <returns></returns>
public static IEnumerable<T> GetAllItems<T>() where T : struct
{
foreach (object item in Enum.GetValues(typeof(T)))
{
yield return (T)item;
}
}
/// <summary>
/// Gets all combined items from an enum value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">The value.</param>
/// <returns></returns>
/// <example>
/// Displays ValueA and ValueB.
/// <code>
/// EnumExample dummy = EnumExample.Combi;
/// foreach (var item in dummy.GetAllSelectedItems<EnumExample>())
/// {
/// Console.WriteLine(item);
/// }
/// </code>
/// </example>
public static IEnumerable<T> GetAllSelectedItems<T>(this Enum value)
{
int valueAsInt = Convert.ToInt32(value, CultureInfo.InvariantCulture);
foreach (object item in Enum.GetValues(typeof(T)))
{
int itemAsInt = Convert.ToInt32(item, CultureInfo.InvariantCulture);
if (itemAsInt == (valueAsInt & itemAsInt))
{
yield return (T)item;
}
}
}
/// <summary>
/// Determines whether the enum value contains a specific value.
/// </summary>
/// <param name="value">The value.</param>
/// <param name="request">The request.</param>
/// <returns>
/// <c>true</c> if value contains the specified value; otherwise, <c>false</c>.
/// </returns>
/// <example>
/// <code>
/// EnumExample dummy = EnumExample.Combi;
/// if (dummy.Contains<EnumExample>(EnumExample.ValueA))
/// {
/// Console.WriteLine("dummy contains EnumExample.ValueA");
/// }
/// </code>
/// </example>
public static bool Contains<T>(this Enum value, T request)
{
int valueAsInt = Convert.ToInt32(value, CultureInfo.InvariantCulture);
int requestAsInt = Convert.ToInt32(request, CultureInfo.InvariantCulture);
if (requestAsInt == (valueAsInt & requestAsInt))
{
return true;
}
return false;
}
}
يجب تزيين التعداد نفسه باستخدام FlagsAttribute
[Flags]
public enum EnumExample
{
ValueA = 1,
ValueB = 2,
ValueC = 4,
ValueD = 8,
Combi = ValueA | ValueB
}
لا تدعم بعض إصدارات .NET Framework Enum.GetValues
. إليك حلاً جيدًا من Ideas 2.0: Enum.GetValues in Compact Framework :
public Enum[] GetValues(Enum enumeration)
{
FieldInfo[] fields = enumeration.GetType().GetFields(BindingFlags.Static | BindingFlags.Public);
Enum[] enumerations = new Enum[fields.Length];
for (var i = 0; i < fields.Length; i++)
enumerations[i] = (Enum) fields[i].GetValue(enumeration);
return enumerations;
}
كما هو الحال مع أي رمز يتضمن انعكاس ، يجب عليك اتخاذ خطوات لضمان تشغيله مرة واحدة فقط وتخزين النتائج مؤقتًا.
لماذا لا أحد يستخدم Cast<T>
؟
var suits = Enum.GetValues(typeof(Suit)).Cast<Suit>();
هناك تذهب IEnumerable<Suit>
.
أعتقد أن هذا أكثر فعالية من الاقتراحات الأخرى لأنه لا يتم استدعاء GetValues()
في كل مرة يكون لديك حلقة. بل هو أيضا أكثر إيجازا. وتحصل على خطأ وقت الترجمة وليس استثناء وقت التشغيل إذا Suit
ليس enum
.
EnumLoop<Suit>.ForEach((suit) => {
DoSomethingWith(suit);
});
EnumLoop
لديه هذا التعريف العام تمامًا:
class EnumLoop<Key> where Key : struct, IConvertible {
static readonly Key[] arr = (Key[])Enum.GetValues(typeof(Key));
static internal void ForEach(Action<Key> act) {
for (int i = 0; i < arr.Length; i++) {
act(arr[i]);
}
}
}
لن تحصل على Enum.GetValues()
في Silverlight.
نشر المدونة الأصلية بواسطة Einar Ingebrigtsen :
public class EnumHelper
{
public static T[] GetValues<T>()
{
Type enumType = typeof(T);
if (!enumType.IsEnum)
{
throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
}
List<T> values = new List<T>();
var fields = from field in enumType.GetFields()
where field.IsLiteral
select field;
foreach (FieldInfo field in fields)
{
object value = field.GetValue(enumType);
values.Add((T)value);
}
return values.ToArray();
}
public static object[] GetValues(Type enumType)
{
if (!enumType.IsEnum)
{
throw new ArgumentException("Type '" + enumType.Name + "' is not an enum");
}
List<object> values = new List<object>();
var fields = from field in enumType.GetFields()
where field.IsLiteral
select field;
foreach (FieldInfo field in fields)
{
object value = field.GetValue(enumType);
values.Add(value);
}
return values.ToArray();
}
}
فقط لإضافة الحل الخاص بي ، والذي يعمل في إطار مضغوط (3.5) ويدعم فحص النوع في وقت الترجمة :
public static List<T> GetEnumValues<T>() where T : new() {
T valueType = new T();
return typeof(T).GetFields()
.Select(fieldInfo => (T)fieldInfo.GetValue(valueType))
.Distinct()
.ToList();
}
public static List<String> GetEnumNames<T>() {
return typeof (T).GetFields()
.Select(info => info.Name)
.Distinct()
.ToList();
}
- إذا كان أي شخص يعرف كيفية التخلص من T valueType = new T()
، سأكون سعيدًا لرؤية حل.
تبدو المكالمة كما يلي:
List<MyEnum> result = Utils.GetEnumValues<MyEnum>();
أعتقد أنك يمكن أن تستخدم
Enum.GetNames(Suit)
public void PrintAllSuits()
{
foreach(string suit in Enum.GetNames(typeof(Suits)))
{
Console.WriteLine(suit);
}
}
foreach (Suit suit in Enum.GetValues(typeof(Suit))) { }
سمعت شائعات غامضة بأن هذا بطيء بشكل رهيب. أي أحد يعرف؟ - أوريون إدواردز 15 أكتوبر 2008 في 1:31 7
أعتقد أن التخزين المؤقت للصفيف سيسرعه إلى حد كبير. يبدو أنك تحصل على مجموعة جديدة (من خلال الانعكاس) في كل مرة. بدلا:
Array enums = Enum.GetValues(typeof(Suit));
foreach (Suit suitEnum in enums)
{
DoSomething(suitEnum);
}
هذا على الأقل أسرع قليلا ، جا؟
ثلاث طرق:
1. Enum.GetValues(type) //since .NET 1.1, not in silverlight or compact framewok
2. type.GetEnumValues() //only on .NET 4 and above
3. type.GetFields().Where(x => x.IsLiteral).Select(x => x.GetValue(null)) //works everywhere
لست متأكدًا من سبب عرض GetEnumValues
على مثيل النوع ، فهو غير قابل للقراءة على الإطلاق بالنسبة لي.
إن وجود فصل مساعد مثل Enum<T>
هو الأكثر قابلية للقراءة وتنسى بالنسبة لي:
public static class Enum<T> where T : struct, IComparable, IFormattable, IConvertible
{
public static IEnumerable<T> GetValues()
{
return (T[])Enum.GetValues(typeof(T));
}
public static IEnumerable<string> GetNames()
{
return Enum.GetNames(typeof(T));
}
}
أنت الآن تتصل:
Enum<Suit>.GetValues();
//or
Enum.GetValues(typeof(Suit)); //pretty consistent style
يمكن للمرء أيضًا استخدام نوع من التخزين المؤقت إذا كان الأداء مهمًا ، لكنني لا أتوقع أن تكون هذه مشكلة على الإطلاق
public static class Enum<T> where T : struct, IComparable, IFormattable, IConvertible
{
//lazily loaded
static T[] values;
static string[] names;
public static IEnumerable<T> GetValues()
{
return values ?? (values = (T[])Enum.GetValues(typeof(T)));
}
public static IEnumerable<string> GetNames()
{
return names ?? (names = Enum.GetNames(typeof(T)));
}
}
ماذا بحق الجحيم سألقي به بنسيين ، فقط من خلال الجمع بين أفضل الإجابات التي أجريها مع امتداد بسيط للغاية
public static class EnumExtensions
{
/// <summary>
/// Gets all items for an enum value.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="value">The value.</param>
/// <returns></returns>
public static IEnumerable<T> GetAllItems<T>(this T value) where T : Enum
{
return (T[])Enum.GetValues(typeof (T));
}
}
نظيفة بسيطة وبتعليق @ جيبي ستيغ نيلسن بسرعة.
هناك طريقتان لتكرار Enum
:
1. var values = Enum.GetValues(typeof(myenum))
2. var values = Enum.GetNames(typeof(myenum))
الأولى ستمنحك القيم في النموذج على صفيفobject
، والثاني سيمنحك القيم في شكل صفيفString
.
استخدمه في حلقة foreach
كما يلي:
foreach(var value in values)
{
//Do operations here
}
إذا كنت بحاجة إلى التحقق من السرعة والكتابة في وقت البناء والتشغيل ، فإن طريقة المساعدة هذه أفضل من استخدام LINQ لإلقاء كل عنصر:
public static T[] GetEnumValues<T>() where T : struct, IComparable, IFormattable, IConvertible
{
if (typeof(T).BaseType != typeof(Enum))
{
throw new ArgumentException(string.Format("{0} is not of type System.Enum", typeof(T)));
}
return Enum.GetValues(typeof(T)) as T[];
}
ويمكنك استخدامه مثل أدناه:
static readonly YourEnum[] _values = GetEnumValues<YourEnum>();
بالطبع يمكنك العودة IEnumerable<T>
، لكن هذا لا يشتري لك شيئًا هنا.
إذا كانت قيم التعداد تتراوح بدقة من 0 إلى n - 1 ، فإن البديل العام:
public void EnumerateEnum<T>()
{
int length = Enum.GetValues(typeof(T)).Length;
for (var i = 0; i < length; i++)
{
var @enum = (T)(object)i;
}
}
إذا كانت قيم التعداد متجاورة ويمكنك توفير العنصر الأول والأخير من التعداد ، عندئذٍ:
public void EnumerateEnum()
{
for (var i = Suit.Spade; i <= Suit.Diamond; i++)
{
var @enum = i;
}
}
ولكن هذا ليس التعداد بدقة ، فقط حلقات. الطريقة الثانية هي أسرع بكثير من أي نهج آخر على الرغم من ...
فيما يلي مثال عملي لإنشاء خيارات تحديد لـ DDL
var resman = ViewModelResources.TimeFrame.ResourceManager;
ViewBag.TimeFrames = from MapOverlayTimeFrames timeFrame
in Enum.GetValues(typeof(MapOverlayTimeFrames))
select new SelectListItem
{
Value = timeFrame.ToString(),
Text = resman.GetString(timeFrame.ToString()) ?? timeFrame.ToString()
};
foreach (Suit suit in Enum.GetValues(typeof(Suit)))
{
}
(تحتوي الإجابة المقبولة الحالية على صورة لا أعتقد أنها ضرورية (على الرغم من أنني قد أكون مخطئًا).)
يظهر هذا السؤال في الفصل 10 من " C # خطوة بخطوة 2013 "
يستخدم المؤلف حلقة مزدوجة للتكرار من خلال زوج من العدادات (لإنشاء مجموعة بطاقات كاملة):
class Pack
{
public const int NumSuits = 4;
public const int CardsPerSuit = 13;
private PlayingCard[,] cardPack;
public Pack()
{
this.cardPack = new PlayingCard[NumSuits, CardsPerSuit];
for (Suit suit = Suit.Clubs; suit <= Suit.Spades; suit++)
{
for (Value value = Value.Two; value <= Value.Ace; value++)
{
cardPack[(int)suit, (int)value] = new PlayingCard(suit, value);
}
}
}
}
في هذه الحالة ، Suit
و Value
كلاهما تعدادان:
enum Suit { Clubs, Diamonds, Hearts, Spades }
enum Value { Two, Three, Four, Five, Six, Seven, Eight, Nine, Ten, Jack, Queen, King, Ace}
و PlayingCard
هو كائن بطاقة ذو Suit
و Value
:
class PlayingCard
{
private readonly Suit suit;
private readonly Value value;
public PlayingCard(Suit s, Value v)
{
this.suit = s;
this.value = v;
}
}
أعلم أن الأمر فوضوي بعض الشيء ، لكن إذا كنت من محبي الخطوط الفردية ، فإليك واحدة:
((Suit[])Enum.GetValues(typeof(Suit))).ToList().ForEach(i => DoSomething(i));
ماذا لو كنت تعرف أن النوع سيكون enum
، لكنك لا تعرف ما هو النوع الدقيق في وقت الترجمة؟
public class EnumHelper
{
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
public static IEnumerable getListOfEnum(Type type)
{
MethodInfo getValuesMethod = typeof(EnumHelper).GetMethod("GetValues").MakeGenericMethod(type);
return (IEnumerable)getValuesMethod.Invoke(null, null);
}
}
تستخدم الطريقة getListOfEnum
الانعكاس لأخذ أي نوع من التعداد وإرجاع IEnumerable
لجميع قيم التعداد.
الاستعمال:
Type myType = someEnumValue.GetType();
IEnumerable resultEnumerable = getListOfEnum(myType);
foreach (var item in resultEnumerable)
{
Console.WriteLine(String.Format("Item: {0} Value: {1}",item.ToString(),(int)item));
}
طريقة بسيطة وعامة لتحويل التعداد إلى شيء يمكنك التفاعل:
public static Dictionary<int, string> ToList<T>() where T : struct
{
return ((IEnumerable<T>)Enum
.GetValues(typeof(T)))
.ToDictionary(
item => Convert.ToInt32(item),
item => item.ToString());
}
وثم:
var enums = EnumHelper.ToList<MyEnum>();
أضف طريقة public static IEnumerable<T> GetValues<T>()
إلى فصلك ، مثل
public static IEnumerable<T> GetValues<T>()
{
return Enum.GetValues(typeof(T)).Cast<T>();
}
استدعاء وتمرير التعداد الخاص بك ، والآن يمكنك تكرار ذلك باستخدام foreach
public static void EnumerateAllSuitsDemoMethod()
{
// custom method
var foos = GetValues<Suit>();
foreach (var foo in foos)
{
// Do something
}
}
تسمى أنواع enum
"أنواع التعداد" ليس لأنها عبارة عن حاويات "تعداد" القيم (التي ليست كذلك) ، ولكن لأنها محددة بواسطة التعداد القيم المحتملة لمتغير من هذا النوع.
(في الواقع ، هذا أكثر تعقيدًا من ذلك - تعتبر أنواع التعداد نوعًا صحيحًا "أساسيًا" ، مما يعني أن كل قيمة تعداد تتوافق مع قيمة عدد صحيح (هذا عادةً ما يكون ضمنيًا ، ولكن يمكن تحديده يدويًا). تم تصميم C # بطريقة بحيث يمكنك إدخال أي عدد صحيح من هذا النوع في متغير التعداد ، حتى لو لم تكن قيمة "مسمى".)
يمكن استخدام System.Enum.GetNames method لاسترداد مجموعة من السلاسل التي هي أسماء قيم التعداد ، كما يوحي الاسم.
تحرير: يجب أن يكون اقترح System.Enum.GetValues الطريقة بدلاً من ذلك. وجه الفتاة.
كما يمكنك ربط الأعضاء الثابتة العامة للتعداد مباشرة باستخدام الانعكاس:
typeof(Suit).GetMembers(BindingFlags.Public | BindingFlags.Static)
.ToList().ForEach(x => DoSomething(x.Name));