كيف تجتاز مقابلة C#: أهم الأسئلة والإجابات
مقابلة العمل لوظيفة مطور C# / .NET ليست مجرد اختبار للمعرفة التقنية، بل هي أيضًا اختبار للقدرة على التفكير وشرح المفاهيم المعقدة بكلمات بسيطة. في هذه المقالة، قمنا بتحليل الأسئلة الأكثر شيوعًا التي تُطرح في المقابلات، مع أمثلة على الكود والشروحات. ستكون المادة مفيدة لمطوري junior و middle على حد سواء.
1. ما الفرق بين value types و reference types؟
هذا سؤال أساسي ولكنه مهم. في C#، تنقسم جميع الأنواع إلى فئتين:
- Value types (أنواع القيم) — تُخزن في المكدس (stack)، وتُنسخ عند التعيين. أمثلة:
int,double,struct,enum. - Reference types (الأنواع المرجعية) — تُخزن في الكومة (heap)، والمتغير يخزن مرجعًا للكائن. أمثلة:
class,string,array,delegate.
مثال للمقابلة:
int a = 10;int b = a;b = 20;Console.WriteLine(a); // 10 — القيمة لم تتغير
var obj1 = new MyClass { Value = 10 };var obj2 = obj1;obj2.Value = 20;Console.WriteLine(obj1.Value); // 20 — المرجع هو نفسهفي المقابلة، غالبًا ما يُسأل أيضًا عن boxing/unboxing — تحويل value type إلى object والعكس. حاول تجنب ذلك في الكود لأنه يقلل من الأداء.
2. ما هي delegates, events و lambda expressions؟
Delegates هي أنواع تخزن مراجعًا للدوال. Events هي غلاف (wrapper) حول delegates، تُستخدم لتنفيذ نمط "الناشر-المشترك" (publisher-subscriber).
مثال على delegate:
public delegate void MyDelegate(string message);
public static void ShowMessage(string msg) => Console.WriteLine(msg);
MyDelegate del = ShowMessage;del("Hello from delegate");مثال على event:
public class Button{ public event EventHandler Click; public void Press() => Click?.Invoke(this, EventArgs.Empty);}Lambda expressions هي طريقة مختصرة لكتابة الدوال المجهولة (anonymous methods). تُستخدم بنشاط في LINQ:
var numbers = new List<int> { 1, 2, 3, 4, 5 };var even = numbers.Where(x => x % 2 == 0).ToList();في المقابلة، قد يُسأل: "لماذا من الأفضل استخدام events بدلاً من delegates؟" — الإجابة: events تحمي قائمة المشتركين من التعديل الخارجي (لا يمكن استدعاء Invoke من الخارج).
3. كيف يعمل async/await وما الفرق بينه وبين تعدد الخيوط (multithreading)؟
هذا أحد أكثر الأسئلة شيوعًا. async/await هو سكر نحوي (syntactic sugar) للعمل مع العمليات غير المتزامنة (asynchronous operations). إنه لا ينشئ خيطًا (thread) جديدًا، بل يستخدم الخيط الموجود بكفاءة (خيط UI أو خيط من pool).
النقاط الرئيسية:
async— معدّل (modifier) للدالة يسمح باستخدامawait.await— يوقف تنفيذ الدالة مؤقتًا حتى اكتمال المهمة (task)، دون حظر الخيط.- نوع الإرجاع — عادةً
TaskأوTask<T>.
مثال:
public async Task<string> GetDataAsync(){ using var client = new HttpClient(); string result = await client.GetStringAsync("https://api.example.com"); return result;}الفرق عن تعدد الخيوط (multithreading): تعدد الخيوط (Thread, Task.Run) هو تنفيذ متوازٍ للكود على عدة أنوية CPU. Async/await هو عدم تزامن (asynchrony) يحرر الخيط لمهام أخرى أثناء فترة الانتظار (مثل انتظار رد من الخادم).
نصيحة: في المقابلة، قدم مثالًا واقعيًا — تحميل بيانات من الشبكة أو ملف. تجنب استخدام async void (باستثناء معالجات الأحداث) — فقد يؤدي ذلك إلى أخطاء غير معالجة.