تحويل int إلى enum في C#: لماذا يكسر الكود وكيفية الإصلاح بشكل صحيح
\n\nكل مطور C#، حتى مع خبرة بضعة أشهر، سيواجه عاجلاً أم آجلاً السؤال: «How do I cast int to enum in C#?». هذا الاستعلام على Stack Overflow حصد مئات الآلاف من المشاهدات - وليس من دون سبب. قد يبدو الأمر بسيطاً: اكتب (MyEnum)myInt - وانتهى الأمر. لكن الشيطان، كما هو الحال دائماً، في التفاصيل. التحويل غير الصحيح int إلى enum يمكن أن يؤدي إلى استثناءات، أخطاء يصعب اكتشافها، وحتى انهيار خادم الإنتاج.
في هذه المقالة، سنستعرض أهم 5 أخطاء عند تحويل int إلى enum، ونعرض أمثلة عملية بلغة C#، ونقدم خوارزمية واضحة للتحويل الآمن. إذا كنت تكتب بلغة C# وتستخدم التعدادات، فهذه المعلومات ستوفر لك ساعات من التصحيح.
\n\nالخطأ رقم 1: التحويل الساذج دون تحقق - «ماذا لو كان الرقم غير صالح؟»
\n\nالطريقة الأكثر شيوعاً التي يجدها المبتدئون على الإنترنت هي التحويل المباشر:
\n\nenum Status\n{\n Active = 1,\n Inactive = 2,\n Pending = 3\n}\n\nint input = 5; // المستخدم أرسل شيئاً غير صحيح\nStatus status = (Status)input; // بدون خطأ، لكن status == (Status)5\nConsole.WriteLine(status); // الإخراج: 5 - قيمة غير صالحة!\n\n\nسيتم تجميع الكود وتنفيذه دون استثناء. لكن المتغير status سيحتوي الآن على القيمة 5، وهي غير موجودة في التعداد Status. في C#، التعدادات هي في الأساس أعداد صحيحة بأسماء. المترجم لا يتحقق مما إذا كانت القيمة تنتمي إلى مجموعة الثوابت. هذا فخ كلاسيكي: تحويل int إلى enum يعمل تقنياً، لكنه منطقياً خطأ.
كيفية تجنبه: استخدم دائماً الطريقة Enum.IsDefined() قبل التحويل.
if (Enum.IsDefined(typeof(Status), input))\n{\n Status status = (Status)input;\n}\nelse\n{\n // معالجة الخطأ: تسجيل، قيمة افتراضية أو استثناء\n Console.WriteLine($"القيمة غير المسموح بها {input} لـ Status");\n}\n\n\nتذكر: Enum.IsDefined() يعمل ببطء عند الاستدعاءات المتكررة، لكنه حارس مثالي للعمليات الفردية.
الخطأ رقم 2: تجاهل التعدادات ذات العلامات ([Flags])
\n\nعند العمل مع التعدادات المميزة بالسمة [Flags]، يتغير منطق التحقق. Enum.IsDefined() سيعيد false للتركيبات الصحيحة من العلامات، حتى لو كانت صحيحة.
[Flags]\nenum Permissions\n{\n None = 0,\n Read = 1,\n Write = 2,\n Execute = 4\n}\n\nint input = 3; // Read + Write\nif (Enum.IsDefined(typeof(Permissions), input))\n{\n // هذا لن يتم تنفيذه! 3 ليست ثابتاً منفرداً\n}\n\n\nبالنسبة للعلامات، يجب استخدام تحقق آخر: هل جميع البتات في الرقم تتوافق مع قيم محددة.
\n\nbool IsValidFlags<T>(int value) where T : Enum\n{\n int allValues = 0;\n foreach (var v in Enum.GetValues<T>())\n {\n allValues |= Convert.ToInt32(v);\n }\n return (value & ~allValues) == 0;\n}\n\nif (IsValidFlags<Permissions>(input))\n{\n Permissions perms = (Permissions)input; // آمن\n}\n\n\nأو، بشكل أبسط، استخدم التحقق المدمج Enum.IsDefined() لكل علامة على حدة إذا كانت قليلة.
الخطأ رقم 3: إهمال معالجة الأرقام السالبة والتجاوز
\n\nالتعداد في C# يعتمد افتراضياً على int، لكن يمكن أن يكون byte أو short أو long إلخ. إذا قمت بتحويل int إلى تعداد والنوع الأساسي هو byte، فإنك تخاطر بالحصول على استثناء عند التجاوز، أو الأسوأ، تشويه صامت للقيمة.
enum SmallEnum : byte\n{\n A = 0,\n B = 255\n}\n\nint bigValue = 300;\nSmallEnum se = (SmallEnum)bigValue; // خطأ في التجميع؟ لا!\n// لكن القيمة ستُقتطع: se == (SmallEnum)44 (300 % 256)\n