enums - Cast int to enum in C#




casting (18)

كيف يمكن تصوير int إلى enum في C #؟


Answers

هذا يوزع الأعداد الصحيحة أو الأوتار على التعداد المستهدف مع المطابقة الجزئية في dot.NET 4.0 باستخدام مواد بديلة مثل في فئة الأداة المساعدة Tawani أعلاه. أنا أستخدمه لتحويل متغيرات تبديل سطر الأوامر التي قد تكون غير مكتملة. نظرًا لأن التعداد لا يمكن أن يكون خاليًا ، فيجب تقديم قيمة افتراضية منطقية. يمكن أن يطلق عليه هذا:

var result = EnumParser<MyEnum>.Parse(valueToParse, MyEnum.FirstValue);

هنا الرمز:

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;
                }
            }
        }
    }
}

لمعلوماتك: كان السؤال عن الأعداد الصحيحة ، والتي لم يذكرها أحد سيتم أيضا تحويل صريح في Enum.TryParse ()


في بعض الأحيان يكون لديك كائن إلى نوع MyEnum . مثل

var MyEnumType = typeof(MyEnumType);

ثم:

Enum.ToObject(typeof(MyEnum), 3)

يمكن أن تساعدك على تحويل أي بيانات إدخال إلى التعداد المطلوب من المستخدم. لنفترض أن لديك تعدادًا مثل أدناه والذي يكون به int بشكل افتراضي. الرجاء إضافة قيمة افتراضية في أول التعداد الخاص بك. والتي تستخدم في المساعدين medthod عندما لا يوجد تطابق مع قيمة المدخلات.

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;
    }
}

ملحوظة: هنا أحاول تحليل القيمة في int ، لأن enum افتراضياً int إذا قمت بتعريف التعداد مثل هذا وهو نوع بايت .

public enum MediaType : byte
{
    Default,
    Audio,
    Video,
    Image
} 

تحتاج إلى تغيير الإعراب بطريقة المساعد من

int.TryParse(value.ToString(), out  tempType)

إلى

byte.TryParse(value.ToString(), out tempType)

أتحقق من طريقتك في متابعة المدخلات

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);

اسف للغتى الانجليزيه


أعتقد أن الحصول على إجابة كاملة ، يجب أن يعرف الناس كيف يعمل enev داخليًا في .NET.

كيف تعمل الاشياء

التعداد في .NET هو بنية تقوم بتعيين مجموعة من القيم (الحقول) إلى نوع أساسي (الافتراضي هو int ). ومع ذلك ، يمكنك في الواقع اختيار النوع المتكامل الذي يعينه التعداد لـ:

public enum Foo : short

في هذه الحالة ، يتم تعيين التعداد إلى نوع البيانات short ، مما يعني أنه سيتم تخزينه في الذاكرة على أنه قصير وسيتصرف كقصر عند الإدلاء به واستخدامه.

إذا نظرت إليها من وجهة نظر IL ، فإن التعداد (العادي ، int) يشبه هذا:

.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__
}

ما يجب الانتباه إليه هنا هو أن value__ يتم تخزينها بشكل منفصل عن قيم التعداد. في حالة التعداد Foo أعلاه ، يكون نوع value__ هو int16. هذا يعني بشكل أساسي أنه يمكنك تخزين ما تريد في التعداد ، طالما تتطابق الأنواع .

عند هذه النقطة ، أود أن أشير إلى أن System.Enum هو نوع من القيم ، وهو ما يعني أن BarFlag سيأخذ 4 بايت في الذاكرة و Foo سوف يأخذ 2 - على سبيل المثال حجم النوع الأساسي (إنه في الواقع أكثر معقدة من ذلك ، ولكن مهلا ...).

الاجابة

لذا ، إذا كان لديك عدد صحيح تريد تعيينه إلى تعداد ، فإن وقت التشغيل لا يتطلب سوى القيام بأمرين: نسخ 4 بايت وتسمية شيء آخر (اسم التعداد). يكون النسخ ضمنيًا لأن البيانات مخزنة كنوع القيمة - وهذا يعني بشكل أساسي أنه إذا كنت تستخدم شفرة غير مُدارة ، يمكنك ببساطة تبادل التعدادات والأعداد الصحيحة دون نسخ البيانات.

ولجعله آمنًا ، أعتقد أنه من أفضل الممارسات معرفة أن الأنواع الأساسية هي نفسها أو القابلة للتحويل ضمنيًا ولضمان وجود قيم التعداد (لا يتم تحديدها افتراضيًا!).

لمعرفة كيفية عمل ذلك ، جرّب التعليمة البرمجية التالية:

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();
}

لاحظ أن الإرسال إلى e2 يعمل أيضًا! من منظور المجمع أعلاه وهذا منطقي: يتم ملء حقل value__ إما بـ 5 أو 6 وعند استدعاء Console.WriteLine ToString() ، يتم حل اسم e1 بينما لا يكون اسم e2 غير.

إذا لم يكن هذا هو ما قصدته ، فاستخدم Enum.IsDefined(typeof(MyEnum), 6) للتحقق مما إذا كانت القيمة التي Enum.IsDefined(typeof(MyEnum), 6) خرائط إلى تعداد محدد.

لاحظ أيضًا أني صريح حول النوع الأساسي للتعداد ، على الرغم من أن المحول البرمجي يتحقق بالفعل من هذا. أنا أفعل هذا لضمان عدم التعرض لأية مفاجآت على الطريق. لرؤية هذه المفاجآت أثناء العمل ، يمكنك استخدام الشفرة التالية (في الواقع لقد رأيت هذا يحدث كثيرًا في رمز قاعدة البيانات):

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();
}

لتحويل سلسلة إلى ENUM أو int إلى ENUM constant ، نحتاج إلى استخدام الدالة Enum.Parse. في ما يلي مقطع فيديو youtube https://www.youtube.com/watch?v=4nhx4VwdRDk الذي يتم عرضه فعليًا مع سلسلة وينطبق الشيء نفسه على int.

يذهب الرمز كما هو موضح أدناه حيث "أحمر" هو السلسلة و "MyColors" هو لون ENUM الذي يحتوي على ثوابت الألوان.

MyColors EnumColors = (MyColors)Enum.Parse(typeof(MyColors), "Red");

هذا عبارة عن أسلوب تحويل آمن علم التعداد:

public static bool TryConvertToEnum<T>(this int instance, out T result)
  where T: struct
{
  var enumType = typeof (T);
  if (!enumType.IsEnum)
  {
    throw new ArgumentException("The generic type must be an enum.");
  }
  var success = Enum.IsDefined(enumType, instance);
  if (success)
  {
    result = (T)Enum.ToObject(enumType, instance);
  }
  else
  {
    result = default(T);
  }
  return success;
}

في حالتي ، كنت بحاجة إلى إعادة التعداد من خدمة WCF. أنا أيضا في حاجة إلى اسم مألوف ، وليس فقط التعداد.ToString ().

هنا صنف 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;
    }
}

إليك طريقة ملحق تحصل على الوصف من التعداد.

    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();
        }
    }

التنفيذ:

return EnumMember.ConvertToList<YourType>();

خذ المثال التالي:

int one = 1;
MyEnum e = (MyEnum)one;

إذا كان لديك عدد صحيح يعمل كقناع نقطي ويمكن أن يمثل قيمة واحدة أو أكثر في تعداد [Flags] ، فيمكنك استخدام هذا الرمز لتحليل قيم العلامات الفردية في قائمة:

for (var flagIterator = 0x1; flagIterator <= 0x80000000; flagIterator <<= 1)
{
    // Check to see if the current flag exists in the bit mask
    if ((intValue & flagIterator) != 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), flagIterator))
            ListOfEnumValues.Add((MyEnum)flagIterator);
    }
}

أنا أستخدم هذه القطعة من التعليمات البرمجية لإلقاء نظرة على التعداد الخاص بي:

if (typeof(YourEnum).IsEnumDefined(valueToCast)) return (YourEnum)valueToCast;
else { //handle it here, if its not defined }

أجد أنه أفضل حل.


من سلسلة:

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.")

من int:

YourEnum foo = (YourEnum)yourInt;

تحديث:

من الرقم يمكنك أيضا

YourEnum foo = (YourEnum)Enum.ToObject(typeof(YourEnum) , yourInt);

الابتعاد قليلا عن السؤال الأصلي ، لكنني وجدت إجابة على سؤال احصل على قيمة int من التعداد مفيدة. إنشاء فئة ثابتة مع خصائص public const int ، مما يسمح لك بجمع مجموعة من الثوابت int ذات الصلة بسهولة ، ومن ثم لا يلزم إرسالها إلى int عند استخدامها.

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;
}

من الواضح أن بعض وظائف نوع التعداد سوف تُفقد ، ولكن من أجل تخزين مجموعة من ثوابت هوية قاعدة البيانات ، يبدو الأمر وكأنه حل أنيق.



بالنسبة للقيم الرقمية ، يعد هذا أكثر أمانًا حيث إنه سيعرض أي كائن مهما كان:

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;
    }
}

أدناه هو فئة فائدة لطيفة 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;
    }
}

لا أعرف بعد الآن أين يمكنني الحصول على جزء من ملحق التوسيع هذا ، لكنه من . أنا آسف على هذا! لكنني أخذت هذا وتعديله للتعداد مع الأعلام. بالنسبة إلى التعدادات مع الأعلام ، قمت بهذا:

  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;
     }
  }

مثال:

[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;

فقط ألقيها:

MyEnum e = (MyEnum)3;

يمكنك التحقق مما إذا كان في النطاق باستخدام Enum.IsDefined :

if (Enum.IsDefined(typeof(MyEnum), 3)) { ... }

المثال الذي أود اقتراحه "للحصول على قيمة" int "من التعداد هو"

public enum Sample
{Book =1, Pen=2, Pencil =3}

int answer = (int)Sample.Book;

الآن سيكون الجواب 1.

آمل أن هذا قد يساعد شخص ما.





c# enums casting