البرمجة الوظيفية في لغة C#: نهج حديث للتطوير
البرمجة الوظيفية (FP) هي نموذج يتم فيه التعامل مع الحساب على أنه تقييم للدوال الرياضية وتتجنب تغيير الحالة والبيانات القابلة للتغيير. على الرغم من أن لغة C# أُنشئت في الأصل كلغة موجهة للكائنات، إلا أنها بدأت منذ الإصدار 3.0 في دمج عناصر النهج الوظيفي بشكل نشط. اليوم، البرمجة الوظيفية في C# ليست مجرد موضة عابرة، بل هي أداة قوية لكتابة كود أكثر قابلية للتنبؤ والاختبار والأمان في التعامل مع التزامن.
في هذه المقالة، سنقوم بتحليل المفاهيم الرئيسية للبرمجة الوظيفية كما تُطبق في C#: الدوال النقية، ثبات البيانات، LINQ، الإغلاقات، وتعبيرات اللامدا. سترى كيف تساعد هذه التقنيات في كتابة كود موجز وموثوق في بيئة .NET.
1. الدوال النقية وغياب الآثار الجانبية
الدالة النقية هي دالة:
- تعيد دائمًا نفس النتيجة لنفس الوسائط (الشفافية المرجعية).
- ليس لها آثار جانبية (لا تعدّل المتغيرات العامة، ولا تقوم بالإدخال/الإخراج، ولا تغيّر الوسائط الممررة).
في C#، قد تبدو الدالة النقية كالتالي:
// Pure functionpublic int AddPure(int a, int b){ return a + b;}
// NOT a pure function (side effect — console output and modification of a global variable)private int _state = 0;public int AddImpure(int a, int b){ _state++; Console.WriteLine("Function call"); return a + b + _state;}مزايا الدوال النقية واضحة: فهي سهلة الاختبار، يمكن التنبؤ بها، ويمكن استدعاؤها بأمان من خيوط متوازية. حاول استخراج كل المنطق غير المرتبط بالإدخال/الإخراج إلى دوال نقية.
2. ثبات البيانات
تشجع البرمجة الوظيفية على العمل مع البيانات غير القابلة للتغيير. بدلاً من تعديل كائن موجود، تقوم بإنشاء كائن جديد مع الخصائص المعدلة. في C#، تعتبر الأدوات التالية ممتازة لهذا الغرض:
- record (اعتبارًا من C# 9) — نوع مرجعي مع مساواة قائمة على القيمة وثبات افتراضي.
- struct — للهياكل الصغيرة غير القابلة للتغيير (مثل الإحداثيات، المال).
- IEnumerable<T> — للمجموعات غير القابلة للتغيير عبر LINQ.
مثال باستخدام record:
public record Person(string Name, int Age);
// Using a with-expression to create a copy with modificationsvar original = new Person("Alexey", 30);var updated = original with { Age = 31 };
Console.WriteLine(original); // Person { Name = Alexey, Age = 30 }Console.WriteLine(updated); // Person { Name = Alexey, Age = 31 }هذا النهج يمنع التعديل العرضي للبيانات في مكان واحد من التأثير على أجزاء أخرى من البرنامج.
3. LINQ — استعلامات البيانات الوظيفية
LINQ (استعلام اللغة المتكامل) هو ربما المثال الأبرز على النهج الوظيفي في C#. يسمح بمعالجة المجموعات بأسلوب تصريحي باستخدام سلاسل الدوال.
دوال LINQ الوظيفية الرئيسية:
Select— تحويل كل عنصر (مشابه لـ map).Where— التصفية (مشابه لـ filter).Aggregate— الطي (مشابه لـ reduce).SelectMany— تسوية المجموعات المتداخلة (flatMap).
مثال: إيجاد مجموع مربعات الأعداد الزوجية.
int[] numbers = { 1, 2, 3, 4, 5, 6 };
// Imperative styleint sumImperative = 0;foreach (var num in numbers){ if (num % 2 == 0) { sumImperative += num * num; }}
// Functional style with LINQint sumFunctional = numbers .Where(n => n % 2 == 0) // filtering .Select(n => n * n) // transformation .Sum(); // aggregation
C