البرمجة التفاعلية في C# (.NET): دليل شامل مع Rx.NET
\n\nالبرمجة التفاعلية هي نموذج تطوير يركز على تدفقات البيانات غير المتزامنة ونشر التغييرات. في نظام C# (.NET)، الأداة الرئيسية لتنفيذ هذا النهج هي مكتبة Reactive Extensions (Rx.NET). تتيح لك العمل مع تسلسلات البيانات التي تتغير بمرور الوقت بنفس سهولة العمل مع المجموعات العادية عبر LINQ.
\n\nفي هذه المقالة، سنشرح المفاهيم الأساسية للبرمجة التفاعلية، ونستعرض المكونات الرئيسية لـ Rx.NET، ونقدم أمثلة عملية على الكود للموقع التعليمي PythonLib.
\n\nالمفاهيم الأساسية للبرمجة التفاعلية
\n\nفي جوهر Rx.NET توجد واجهتان:
\n- \n
- IObservable<T> — مصدر البيانات (تسلسل قابل للملاحظة) يمكنه إرسال عناصر أو أخطاء أو إشارة اكتمال. \n
- IObserver<T> — المشترك (مراقب) الذي يتلقى الإشعارات من المصدر:
OnNext،OnError،OnCompleted. \n
الفكرة الأساسية: بدلاً من استقصاء المصدر (نموذج السحب)، يتفاعل المشترك مع الأحداث (نموذج الدفع). هذا مفيد بشكل خاص لمعالجة أحداث واجهة المستخدم، وطلبات الشبكة، وتدفقات البيانات من أجهزة الاستشعار، أو أي عمليات غير متزامنة أخرى.
\n\nبدء العمل مع Rx.NET
\n\nلاستخدام Rx.NET في مشروع C#، قم بتثبيت حزمة NuGet:
\ndotnet add package System.Reactive\n\nمثال 1: إنشاء والاشتراك في observable
\nلننشئ تسلسلًا بسيطًا من الأرقام يولد قيمًا مع تأخير:
\nusing System;\nusing System.Reactive.Linq;\nusing System.Threading.Tasks;\n\nclass Program\n{\n static async Task Main()\n {\n var observable = Observable\n .Interval(TimeSpan.FromSeconds(1)) // يولد 0, 1, 2... كل ثانية\n .Take(5); // نأخذ أول 5 أرقام فقط\n\n var subscription = observable.Subscribe(\n onNext: number => Console.WriteLine($"تم الاستلام: {number}"),\n onError: error => Console.WriteLine($"خطأ: {error.Message}"),\n onCompleted: () => Console.WriteLine("اكتمل التدفق")\n );\n\n // ننتظر اكتمال التدفق\n await Task.Delay(6000);\n subscription.Dispose(); // إلغاء الاشتراك\n }\n}\n\nمثال 2: التصفية والتحويل باستخدام LINQ
\nيدعم Rx.NET جميع عوامل تشغيل LINQ القياسية، مما يجعل الكود موجزًا:
\nvar values = Observable.Range(1, 10);\n\nvar processed = values\n .Where(x => x % 2 == 0) // الأرقام الزوجية فقط\n .Select(x => x * 10) // نضرب في 10\n .Timestamp(); // نضيف طابعًا زمنيًا\n\nprocessed.Subscribe(x => Console.WriteLine($"[{x.Timestamp}] القيمة: {x.Value}"));\n\nالإمكانيات المتقدمة لـ Rx.NET
\n\nدمج التدفقات
\nيمكنك دمج عدة تسلسلات observable:
\nvar stream1 = Observable.Interval(TimeSpan.FromSeconds(1)).Select(x => $"A{x}");\nvar stream2 = Observable.Interval(TimeSpan.FromSeconds(1.5)).Select(x => $"B{x}");\n\nvar merged = stream1.Merge(stream2); // دمج في تدفق واحد\nmerged.Take(6).Subscribe(Console.WriteLine);\n\nإدارة تعدد المهام
\nيتيح Rx.NET التبديل بسهولة بين سياقات التنفيذ:
\nvar uiScheduler = new SynchronizationContextScheduler(SynchronizationContext.Current);\n\nObservable\n .Interval(TimeSpan.FromSeconds(1))\n .ObserveOn(uiScheduler) // نضمن التنفيذ في سلسلة واجهة المستخدم\n .Subscribe(x => UpdateUI(x)); // تحديث الواجهة\n\nمعالجة الأخطاء
\nيوفر Rx.NET آليات قوية للتعافي من الأعطال:
\nvar faultyStream = Observable.Throw<int>(new Exception("خطأ!"));\n\nvar safeStr