تحويل int إلى enum في C#: 5 أخطاء قاتلة وكيفية تجنبها

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

تحويل int إلى enum في C#: لماذا يكسر الكود وكيفية الإصلاح بشكل صحيح

\n\n

كل مطور C#، حتى مع خبرة بضعة أشهر، سيواجه عاجلاً أم آجلاً السؤال: «How do I cast int to enum in C#?». هذا الاستعلام على Stack Overflow حصد مئات الآلاف من المشاهدات - وليس من دون سبب. قد يبدو الأمر بسيطاً: اكتب (MyEnum)myInt - وانتهى الأمر. لكن الشيطان، كما هو الحال دائماً، في التفاصيل. التحويل غير الصحيح int إلى enum يمكن أن يؤدي إلى استثناءات، أخطاء يصعب اكتشافها، وحتى انهيار خادم الإنتاج.

\n\n

في هذه المقالة، سنستعرض أهم 5 أخطاء عند تحويل int إلى enum، ونعرض أمثلة عملية بلغة C#، ونقدم خوارزمية واضحة للتحويل الآمن. إذا كنت تكتب بلغة C# وتستخدم التعدادات، فهذه المعلومات ستوفر لك ساعات من التصحيح.

\n\n

الخطأ رقم 1: التحويل الساذج دون تحقق - «ماذا لو كان الرقم غير صالح؟»

\n\n

الطريقة الأكثر شيوعاً التي يجدها المبتدئون على الإنترنت هي التحويل المباشر:

\n\n
enum 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 يعمل تقنياً، لكنه منطقياً خطأ.

\n\n

كيفية تجنبه: استخدم دائماً الطريقة Enum.IsDefined() قبل التحويل.

\n\n
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() يعمل ببطء عند الاستدعاءات المتكررة، لكنه حارس مثالي للعمليات الفردية.

\n\n

الخطأ رقم 2: تجاهل التعدادات ذات العلامات ([Flags])

\n\n

عند العمل مع التعدادات المميزة بالسمة [Flags]، يتغير منطق التحقق. Enum.IsDefined() سيعيد false للتركيبات الصحيحة من العلامات، حتى لو كانت صحيحة.

\n\n
[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\n
bool 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() لكل علامة على حدة إذا كانت قليلة.

\n\n

الخطأ رقم 3: إهمال معالجة الأرقام السالبة والتجاوز

\n\n

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

\n\n
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

المدونات

توصيات الكتب