البرمجة الفوقية في C#: عندما يكتب الكود كودًا
تخيل أنك مهندس معماري لا يبني مجرد منزل، بل يبني روبوت بناء يرفع الجدران بنفسه، ويمد الأسلاك، ويدهن الواجهات. في عالم C#، هذا "الروبوت" هو البرمجة الفوقية - فن كتابة برامج تقوم بإنشاء أو تحليل أو تعديل برامج أخرى (أو نفسها) أثناء التنفيذ.
لماذا نحتاج هذا؟ تخيل أنك تكتب عشرات الفئات المتشابهة للتعامل مع JSON، أو تنشئ أنظمة إضافات معقدة، أو تتكاسل عن استدعاء مئات الطرق يدويًا عبر الانعكاس. تتيح لك البرمجة الفوقية في C# أتمتة المهام الروتينية، وإنشاء أطر عمل مرنة، وتسريع التطوير أضعافًا مضاعفة. اليوم سنتناول الركائز الثلاث لهذه التقنية: الانعكاس، أشجار التعبيرات، وتوليد الكود الديناميكي.
هذه المقالة مخصصة لمن يكتبون C# بثقة، لكنهم يريدون النظر تحت غطاء CLR وتعلم السحر الذي يميز كبير المطورين عن متوسط المستوى. هيا بنا!
الانعكاس (Reflection): أشعة سينية لكودك
الانعكاس هو أساس البرمجة الفوقية في C#. يسمح لك بالحصول على معلومات حول الأنواع والطرق والخصائص والحقول أثناء وقت التشغيل، وكذلك استدعاؤها ديناميكيًا. تخيل أنك تنظر إلى كائن وكأنه كتاب مفتوح، ويمكنك قراءة أي صفحة منه.
الحصول على معلومات حول النوع
أبسط طريقة هي استخدام الكلمة المفتاحية typeof أو الطريقة GetType():
Type stringType = typeof(string);Console.WriteLine($"الاسم: {stringType.Name}"); // StringConsole.WriteLine($"مساحة الاسم: {stringType.Namespace}"); // SystemConsole.WriteLine($"هل هو فئة؟ {stringType.IsClass}"); // Trueالاستدعاء الديناميكي للطرق
لنفترض أن لديك فئة Calculator، وتريد استدعاء طريقتها Add، التي لا يُعرف اسمها إلا في وقت التشغيل (مثلاً من ملف إعدادات):
public class Calculator{ public int Add(int a, int b) => a + b;}
// استخدام الانعكاسCalculator calc = new Calculator();Type calcType = typeof(Calculator);MethodInfo? addMethod = calcType.GetMethod("Add");
if (addMethod != null){ int result = (int)addMethod.Invoke(calc, new object[] { 5, 3 }); Console.WriteLine($"النتيجة: {result}"); // 8}متى يكون الانعكاس مفيدًا؟
- التسلسل / إلغاء التسلسل — مكتبات مثل Newtonsoft.Json تستخدم الانعكاس بنشاط.
- الإضافات — تحميل التجميعات الخارجية واستدعاء طرقها.
- الاختبار — الوصول إلى الحقول والطرق الخاصة (على الرغم من أنه من الأفضل عدم فعل ذلك).
هام! الانعكاس عملية بطيئة. إذا كنت تستدعي نفس الطريقة آلاف المرات، فكر في تخزين MethodInfo مؤقتًا أو استخدام المفوضين.
أشجار التعبيرات (Expression Trees): الكود كبيانات
أشجار التعبيرات هي طريقة لتمثيل الكود على شكل هيكل بيانات (شجرة). يمكنك تحليل هذا الكود وتعديله وحتى ترجمته "على الطاير". هذه أداة قوية لإنشاء ORM (Entity Framework)، والمحققين، والاستعلامات الديناميكية.
إنشاء شجرة بسيطة
بدلاً من كتابة تعبير لامدا x => x * 2، نقوم ببنائها يدويًا:
using System.Linq.Expressions;
// إنشاء معامل xParameterExpression param = Expression.Parameter(typeof(int), "x");// إنشاء ثابت 2ConstantExpression constant = Expression.Constant(2);// إنشاء عملية الضرب x * 2BinaryExpression body = Expression.Multiply(param, constant);// تجميع كل شيء في لامدا: x => x * 2Expression<Func<int, int>> lambda = Expression.Lambda<Func<int, int>>(body, param);
// ترجمة وتنفيذFunc<int, int> compiled