Cast int to enum in C#




enums casting (14)

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

https://code.i-harness.com


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

أعتقد أن الحصول على إجابة كاملة ، يجب أن يعرف الناس كيف يعمل 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();
}

إذا كان لديك عدد صحيح يعمل كقناع نقطي ويمكن أن يمثل قيمة واحدة أو أكثر في تعداد [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);
    }
}


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

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

بدلاً من ذلك ، استخدم طريقة ملحق بدلاً من خط واحد:

public static T ToEnum<T>(this string enumString)
{
    return (T) Enum.Parse(typeof (T), enumString);
}

الاستعمال:

Color colorEnum = "Red".ToEnum<Color>();

أو

string color = "Red";
var colorEnum = color.ToEnum<Color>();

طرق مختلفة للإدلاء بها من 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);


 }
}

فقط ألقيها:

MyEnum e = (MyEnum)3;

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

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

في حالتي ، كنت بحاجة إلى إعادة التعداد من خدمة 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>();

فيما يلي طريقة تمديد أفضل قليلاً

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

من سلسلة: (Enum.Parse هو خارج التاريخ ، استخدم Enum.TryParse)

enum Importance
{}

Importance importance;

if (Enum.TryParse(value, out importance))
{
}

من سلسلة:

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

هذا يوزع الأعداد الصحيحة أو الأوتار على التعداد المستهدف مع المطابقة الجزئية في 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 ()


يمكن أن تساعدك على تحويل أي بيانات إدخال إلى التعداد المطلوب من المستخدم. لنفترض أن لديك تعدادًا مثل أدناه والذي يكون به 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);

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





casting