علامتا الاستفهام في C#: ليست خطأ، بل أداة قوية
\n\nتخيل: أنت تكتب كودًا بلغة C#، وفجأة ترى تركيب ??. أول فكرة تتبادر إلى ذهنك — خطأ مطبعي؟ علامة زائدة؟ في الحقيقة، هذا واحد من أكثر عوامل اللغة أناقة وفائدة — عامل دمج القيم الخالية (null-coalescing operator). إذا كنت قد واجهت يومًا NullReferenceException ولعنت كل شيء — فهذا العامل سيكون طوق نجاة لك.
في هذه المقالة، سنشرح ما تعنيه علامتا الاستفهام في C#، وكيفية استخدامهما بشكل صحيح، وما الفرق بينهما وبين العامل الثلاثي، وسنعرض أمثلة حقيقية من الممارسة. هيا بنا!
\n\nما هو العامل ?? في C#؟
\n\nالعامل ?? (علامتا استفهام) هو عامل ثنائي يُرجع المعامل الأيسر إذا لم يكن يساوي null؛ وإلا فإنه يُرجع المعامل الأيمن. ببساطة: "إذا كان اليسار ليس null — خذ اليسار، وإلا خذ اليمين".
التركيب بسيط للغاية:
\n\nvar result = left ?? right;\n\nحيث:
\n- \n
left— قيمة قد تكون null؛ \n right— قيمة افتراضية (لا يمكن أن تكون null إذا كان النوع الأيمن nullable). \n
المثال الأول: النجاة من null
\n\nلنفترض أن لديك متغير string? name (سلسلة nullable). تريد عرض اسم المستخدم، وإذا لم يكن موجودًا — "ضيف":
string? name = GetUserName(); // قد يُرجع null\nstring displayName = name ?? "ضيف";\nConsole.WriteLine(displayName);\n\nبدون العامل ??، كان عليك كتابة:
string displayName = (name != null) ? name : "ضيف";\n\nأوافقك الرأي، الخيار الأول يُقرأ كجملة عادية: "الاسم أو ضيف". جميل، أليس كذلك؟
\n\nالعامل ??=: الجيل الجديد من دمج القيم الخالية
\n\nبدءًا من C# 8.0، ظهر العامل ??= — وهو صيغة مختصرة للإسناد مع دمج القيم الخالية. يُسند قيمة المعامل الأيمن إلى المعامل الأيسر، فقط إذا كان المعامل الأيسر يساوي null.
التركيب:
\n\nleft ??= right;\n\nهذا يعادل:
\n\nif (left == null) left = right;\n\nمثال مع ??=
\n\nList<int>? numbers = null;\nnumbers ??= new List<int>(); // numbers الآن = new List<int>()\nnumbers.Add(42);\nConsole.WriteLine(numbers.Count); // 1\n\nلاحظ: إذا كان numbers قد تمت تهيئته بالفعل (ليس null)، فلن يحدث الإسناد. هذا مثالي للتهيئة البطيئة (lazy initialization).
مقارنة مع العامل الثلاثي (? :)
\n\nكثير من المبتدئين يخلطون بين ?? والعامل الثلاثي ? :. دعنا نوضح الأمر مرة واحدة وإلى الأبد:
- \n
- العامل الثلاثي — هو صيغة مختصرة لـ if-else. يتحقق من أي شرط منطقي:
شرط ? قيمة_إذا_صحيح : قيمة_إذا_خاطئ. \n - العامل ?? — يتحقق فقط من null. هذه حالة خاصة، مصممة لمهمة واحدة. \n
مثال على العامل الثلاثي:
\n\nint age = 18;\nstring status = (age >= 18) ? "بالغ" : "قاصر";\n\np>وإليك ما سيحدث إذا حاولت استبدال ?? بالعامل الثلاثي:\n\nstring? name = null;\nstring displayName = name != null ? name : "ضيف"; // يعمل، لكنه أطول\nstring displayName2 = name ?? "ضيف"; // أقصر وأوضح\n\nالخلاصة: استخدم ?? عندما تحتاج ببساطة إلى استبدال قيمة افتراضية بدلاً من null. لجميع الشروط الأخرى — استخدم العامل الثلاثي.
سلسلة العوامل ??
\n\nيمكنك ربط عدة عوامل ?? في سلسلة. هذا مفيد عندما يكون هناك عدة مصادر محتملة للقيمة:
string? firstChoice = GetFromCache