ref و out في C#: أهم 5 أخطاء للمبتدئين وكيفية تجنبها

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

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

ابدأ الدورة

ref و out في C#: معركة المعدّلات التي يجب أن تربحها

\n\n

إذا سبق لك أن كتبت كودًا بلغة C# وتحتاج إلى إرجاع أكثر من قيمة واحدة من دالة، فبالتأكيد صادفت الكلمتين المفتاحيتين ref و out. للوهلة الأولى، قد يبدو أنهما يفعلان الشيء نفسه – السماح للدالة بتعديل المتغير المُمرَر إليها. لكن الشيطان، كما هو الحال دائمًا، يكمن في التفاصيل. على موقع Stack Overflow، السؤال "ما الفرق بين الكلمتين المفتاحيتين 'ref' و 'out'؟" حصد مئات الآلاف من المشاهدات. لماذا؟ لأن الخلط بينهما هو أحد أكثر الأخطاء شيوعًا للمبتدئين (وحتى للمطورين المحترفين عندما يكتبون كودًا بسرعة).

\n\n

في هذه المقالة، لن نكتفي بسرد التعريفات الجافة. سنقوم بتحليل أهم 5 أخطاء حقيقية يرتكبها المبرمجون عند التعامل مع ref و out، وسنوضح كيفية تجنبها. ستتعرف متى تستخدم كل معدّل، ولماذا out ليس مجرد "ref كسول". هيا بنا!

\n\n

باختصار: فلسفة ref و out

\n\n

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

\n\n

out يشبه أن تقول: "هذا صندوق فارغ، املأه بشيء وأعده إليّ". أنت تعطي صديقك حاوية فارغة، وهو ملزم بملئها. لست مضطرًا لوضع أي شيء فيها مسبقًا.

\n\n

هذا هو الفرق الرئيسي: ref يتطلب أن يكون المتغير مُهيأً قبل تمريره، بينما out يسمح بتمرير متغير غير مُهيأ، لكنه يضمن أن الدالة ستُسند إليه قيمة.

\n\n

الخطأ رقم 1: الخلط في التهيئة

\n\n

أكثر الأخطاء شيوعًا. يحاول المطورون تمرير متغير مُهيأ إلى out – هذا ليس خطأ، لكنه يفقد المعنى. أو العكس، يمررون متغيرًا غير مُهيأ إلى ref – ويحصلون على خطأ في الترجمة.

\n\n

مثال كود (خطأ):

\n
public void Process(ref int x)\n{\n    x = x * 2;\n}\n\n// الاستخدام\nint number; // خطأ! المتغير غير مُهيأ\nProcess(ref number); // CS0165: استخدام متغير محلي "number" لم يتم تعيين قيمة له\n
\n\n

الطريقة الصحيحة:

\n
int number = 10; // يجب التهيئة إجباريًا\nProcess(ref number);\nConsole.WriteLine(number); // 20\n
\n\n

مثال مع out (صحيح):

\n
public void Initialize(out int value)\n{\n    value = 42; // ملزمون بتعيين قيمة\n}\n\nint result; // يمكن تركه بدون تهيئة!\nInitialize(out result);\nConsole.WriteLine(result); // 42\n
\n\n

الخلاصة: إذا كنت بحاجة لتعديل قيمة موجودة – استخدم ref. إذا كانت الدالة يجب أن تنشئ قيمة جديدة "من الصفر" – استخدم out.

\n\n

الخطأ رقم 2: نسيان تعيين قيمة لمعامل out

\n\n

مترجم C# صارم: إذا أعلنت معاملًا على أنه out، فأنت ملزم بتعيين قيمة له قبل الخروج من الدالة (في جميع مسارات الكود). هذا ليس عيبًا، بل ميزة تحميك من السلوك غير المحدد.

\n\n

مثال كود (خطأ):

\n
public bool TryParse(string input, out int result)\n{\n    if (int.TryParse(input, out result))\n    {\n        return true;\n    }\n    // نسينا تعيين قيمة لـ result في حالة الفشل!\n    // المترجم سيظهر خطأ: CS0177\n    return false;\n}\n
\n\n

الطريقة الصحيحة:

\n
public bool TryParseSafe(string input, out int result)\n{\n    if (int.TryParse(input, out var parsed))\n    {\n        result = parsed;\n        return true;\n    }\n    result = 0; // دائمًا نعطي قيمة\n    return false;\n}\n
\n\n

نصيحة

المدونات

توصيات الكتب