مقدمة: لماذا يجب أن يتحدث كودك لغة الأعمال
\n\nتخيل: أنت تكتب تكوينًا لروبوت تداول معقد. بدلاً من مئات الأسطر من if-else والأرقام السحرية، تكتب ببساطة: BuyWhen(Price.CrossesAbove(MA(50))). مديرك، الذي لا يعرف C#، ينظر إلى هذا الكود ويفهم المنطق. هذا ليس سحرًا — هذا DSL على C#.
اللغات الخاصة بالمجال (Domain-Specific Languages, DSL) ليست مجرد موضة عابرة. إنها أداة تحول فوضى التفاصيل التقنية إلى كود أنيق وقابل للقراءة. في هذه المقالة، لن نتحدث فقط عن النظرية — بل سننشئ DSL حقيقيًا على C# من الصفر، ونحلل الأخطاء النموذجية، ونوضح كيفية دمج هذه الممارسة في مشروعك اليوم.
\n\nما هو DSL ولماذا يحتاجه المطور؟
\n\nDSL هي لغة برمجة تم إنشاؤها لحل مشكلة محددة. على عكس اللغة العامة (C#, Java, Python)، تتحدث DSL لغة المجال. في C# هناك نهجان رئيسيان:
\n\n- \n
- DSL داخلي — يُبنى فوق C# باستخدام Fluent API و Expression Trees. تبقى في بيئتك الأصلية. \n
- DSL خارجي — يتطلب تحليلًا (غالبًا عبر Roslyn) ويُولد كود C#. \n
الفائدة الحقيقية لـ DSL: تقليل العبء المعرفي، تقليل عدد الأخطاء (منطق الأعمال منفصل عن التنفيذ التقني)، وتسريع تأهيل المطورين الجدد.
\n\nإنشاء DSL داخلي على C#: دليل خطوة بخطوة
\n\nالخطوة 1: تحديد المجال والتركيب
\n\nلنفترض أننا ننشئ DSL للتحقق من صحة البيانات. بدلاً من:
\n\nif (user.Age < 18 || user.Name == null || user.Email == null)\n throw new ValidationException();\n\nنريد الكتابة هكذا:
\n\nValidate.User(user)\n .MustBeAdult()\n .MustHaveName()\n .MustHaveEmail();\n\nالخطوة 2: Fluent Interface — أساس DSL على C#
\n\nالعنصر الأساسي هو إرجاع this من كل دالة. ننشئ فئة المدقق:
public class UserValidator\n{\n private readonly User _user;\n private readonly List<string> _errors = new();\n\n public UserValidator(User user) => _user = user;\n\n public UserValidator MustBeAdult()\n {\n if (_user.Age < 18)\n _errors.Add("المستخدم قاصر");\n return this;\n }\n\n public UserValidator MustHaveName()\n {\n if (string.IsNullOrWhiteSpace(_user.Name))\n _errors.Add("الاسم مطلوب");\n return this;\n }\n\n public void Validate()\n {\n if (_errors.Any())\n throw new ValidationException(string.Join("; ", _errors));\n }\n}\n\nودالة مصنع لدخول أنيق:
\n\npublic static class Validate\n{\n public static UserValidator User(User user) => new UserValidator(user);\n}\n\nالخطوة 3: إضافة الهياكل الشرطية والسياق
\n\nيجب أن يدعم DSL الحقيقي على C# التفرعات. ننفذ When:
public UserValidator When(bool condition, Func<UserValidator, UserValidator> validatorFunc)\n{\n if (condition)\n return validatorFunc(this);\n return this;\n}\n\nالاستخدام:
\n\nValidate.User(user)\n .MustHaveName()\n .When(user.Age > 18, v => v.MustBeAdult());\n\nالمستوى المتقدم: DSL مع Expression Trees على C#
\n\nلبناء استعلامات ديناميكية (ORM, قواعد) نستخدم Expression<Func<T, bool>>. ننشئ باني القواعد:
public class RuleBuilder<T>\n{\n private Expression<Func<T, bool>> _expression;\n\n public RuleBuilder(Expression<Func<T, bool>> expression) => _expression = expression;\n\n public RuleBuilder<T> And(Expression<Func<T, bool>> other)\n {\n var andExpression = Ex