Generics في C#: لماذا هي ضرورية وكيفية استخدامها
\n\nعند التطوير بلغة C#، عاجلاً أم آجلاً، يواجه كل مبرمج موقفاً حيث يجب تطبيق نفس الخوارزمية على أنواع بيانات مختلفة. في السابق، كان عليك إما كتابة عدة إصدارات من نفس الطريقة أو استخدام النوع object، مما يؤدي إلى فقدان الأداء وخطر الأخطاء. حل هذه المشكلة هو Generics (الأنواع العامة). في هذه المقالة، سنشرح ما هي generics، ولماذا هي ضرورية وكيفية استخدامها بشكل صحيح في C#.
ما هي Generics في C#؟
\n\nGenerics (التعميمات) هي آلية في لغة C# تسمح بإنشاء فئات وطرق وواجهات ومفوضات تعمل مع أنواع بيانات مختلفة دون فقدان الكتابة الصارمة. بدلاً من كتابة كود لكل نوع على حدة، تقوم بإنشاء قالب واحد عام يقوم بتعويض النوع المطلوب أثناء وقت الترجمة.
\n\nتخيل أنك بحاجة لكتابة طريقة لتبادل قيم متغيرين. بدون generics، سيكون عليك إنشاء طرق منفصلة لـ int و string و double وهكذا. مع generics، تكتب طريقة واحدة تعمل مع أي نوع.
إليك مثال بسيط لتعريف طريقة generic:
\n\npublic void Swap<T>(ref T a, ref T b)\n{\n T temp = a;\n a = b;\n b = temp;\n}\n\nهنا <T> هو معامل النوع. الحرف T هو تسمية شائعة (من Type)، لكن يمكنك استخدام أي اسم. عند استدعاء الطريقة، تحدد النوع المحدد:
int x = 5, y = 10;\nSwap<int>(ref x, ref y);\n// الآن x = 10, y = 5\n\nstring first = "Hello", second = "World";\nSwap<string>(ref first, ref second);\n// الآن first = "World", second = "Hello"\n\nلماذا نحتاج Generics: المزايا الرئيسية
\n\nاستخدام generics يوفر عدة مزايا مهمة تجعل الكود أفضل وأكثر أماناً.
\n\n1. أمان الأنواع (Type Safety)
\nعلى عكس استخدام object، تقوم generics بالتحقق من الأنواع في مرحلة الترجمة. لن تتمكن من تمرير سلسلة نصية عن طريق الخطأ حيث يُتوقع رقم. سيشير المترجم فوراً إلى الخطأ.
2. الأداء
\nعند استخدام object، يحدث التغليف (boxing) للأنواع القيمية (int, double, struct) إلى نوع مرجعي وإلغاء التغليف (unboxing) العكسي. هذه عمليات مكلفة. Generics تلغي هذه العمليات تماماً، لأن المترجم يولد كوداً متخصصاً لكل نوع.
3. إعادة استخدام الكود
\nلست بحاجة لكتابة نفس الخوارزمية لأنواع مختلفة. يمكن لفئة أو طريقة generic واحدة العمل مع آلاف الأنواع المختلفة.
\n\n4. قابلية القراءة والصيانة
\nيصبح الكود أنظف وأكثر وضوحاً. ترى بوضوح الأنواع التي تعمل معها الطريقة أو الفئة، ويتم فصل المنطق عن أنواع البيانات المحددة.
\n\nكيفية استخدام Generics: أمثلة عملية
\n\nدعنا نستعرض عدة سيناريوهات حقيقية لاستخدام generics في C#.
\n\nفئات Generic
\nالمثال الأكثر شيوعاً هو المجموعات. بدلاً من إنشاء فئة خاصة بك لتخزين قائمة أرقام أو نصوص أو كائنات مخصصة، تستخدم List<T>:
List<int> numbers = new List<int>();\nnumbers.Add(1);\nnumbers.Add(2);\n\nList<string> names = new List<string>();\nnames.Add("Alice");\nnames.Add("Bob");\n\n// فئة generic خاصة بك\npublic class Repository<T>\n{\n private List<T> _items = new List<T>();\n\n public void Add(T item) => _items.Add(item);\n public T Get(int index) => _items[index];\n}\n\nRepository<int> intRepo = new Repository<int>();\nintRepo.Add(100);\nint value = intRepo.Get(0); // 100\n\nطرق Generic
\nيمكن أن تكون الطرق عامة حتى داخل الفئات العادية:
\n