DSL على C#: إنشاء لغة برمجة خاصة بك في أمسية

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

مقدمة: لماذا يجب أن يتحدث كودك لغة الأعمال

\n\n

تخيل: أنت تكتب تكوينًا لروبوت تداول معقد. بدلاً من مئات الأسطر من if-else والأرقام السحرية، تكتب ببساطة: BuyWhen(Price.CrossesAbove(MA(50))). مديرك، الذي لا يعرف C#، ينظر إلى هذا الكود ويفهم المنطق. هذا ليس سحرًا — هذا DSL على C#.

\n\n

اللغات الخاصة بالمجال (Domain-Specific Languages, DSL) ليست مجرد موضة عابرة. إنها أداة تحول فوضى التفاصيل التقنية إلى كود أنيق وقابل للقراءة. في هذه المقالة، لن نتحدث فقط عن النظرية — بل سننشئ DSL حقيقيًا على C# من الصفر، ونحلل الأخطاء النموذجية، ونوضح كيفية دمج هذه الممارسة في مشروعك اليوم.

\n\n

ما هو DSL ولماذا يحتاجه المطور؟

\n\n

DSL هي لغة برمجة تم إنشاؤها لحل مشكلة محددة. على عكس اللغة العامة (C#, Java, Python)، تتحدث DSL لغة المجال. في C# هناك نهجان رئيسيان:

\n\n
    \n
  • DSL داخلي — يُبنى فوق C# باستخدام Fluent API و Expression Trees. تبقى في بيئتك الأصلية.
  • \n
  • DSL خارجي — يتطلب تحليلًا (غالبًا عبر Roslyn) ويُولد كود C#.
  • \n
\n\n

الفائدة الحقيقية لـ DSL: تقليل العبء المعرفي، تقليل عدد الأخطاء (منطق الأعمال منفصل عن التنفيذ التقني)، وتسريع تأهيل المطورين الجدد.

\n\n

إنشاء DSL داخلي على C#: دليل خطوة بخطوة

\n\n

الخطوة 1: تحديد المجال والتركيب

\n\n

لنفترض أننا ننشئ DSL للتحقق من صحة البيانات. بدلاً من:

\n\n
if (user.Age < 18 || user.Name == null || user.Email == null)\n    throw new ValidationException();
\n\n

نريد الكتابة هكذا:

\n\n
Validate.User(user)\n    .MustBeAdult()\n    .MustHaveName()\n    .MustHaveEmail();
\n\n

الخطوة 2: Fluent Interface — أساس DSL على C#

\n\n

العنصر الأساسي هو إرجاع this من كل دالة. ننشئ فئة المدقق:

\n\n
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\n
public static class Validate\n{\n    public static UserValidator User(User user) => new UserValidator(user);\n}
\n\n

الخطوة 3: إضافة الهياكل الشرطية والسياق

\n\n

يجب أن يدعم DSL الحقيقي على C# التفرعات. ننفذ When:

\n\n
public UserValidator When(bool condition, Func<UserValidator, UserValidator> validatorFunc)\n{\n    if (condition)\n        return validatorFunc(this);\n    return this;\n}
\n\n

الاستخدام:

\n\n
Validate.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>>. ننشئ باني القواعد:

\n\n
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                

المدونات

توصيات الكتب