حقن التبعيات في C#: دليل بسيط للمبتدئين

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

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

ابدأ الدورة

ما هو حقن التبعيات (DI) في C# ولماذا هو ضروري؟

\n\n

حقن التبعيات (Dependency Injection) هو نمط تصميم يسمح بجعل الكود أكثر مرونة وقابلية للاختبار والصيانة. بدلاً من أن يقوم الفصل (class) بإنشاء الكائنات التي يعتمد عليها بنفسه، يتم "حقن" هذه الكائنات من الخارج. هذا أحد المبادئ الأساسية التي تقوم عليها التطوير الحديث باستخدام C# و.NET.

\n\n

تخيل أنك تكتب تطبيقًا لإرسال إشعارات البريد الإلكتروني. إذا كان الفصل الخاص بك NotificationService سيقوم بإنشاء مثيل مباشر من SmtpClient، فعند تغيير خادم البريد أو الحاجة لاستخدام طريقة إرسال أخرى (مثل عبر API)، سيتعين عليك إعادة كتابة الكود. DI يحل هذه المشكلة.

\n\n

المشكلة بدون حقن التبعيات

\n\n

لننظر إلى مثال نموذجي لكود سيء حيث يتم إنشاء التبعية داخل الفصل:

\n\n
public class EmailService\n{\n    private SmtpClient _smtpClient;\n\n    public EmailService()\n    {\n        // ربط صارم بتطبيق محدد\n        _smtpClient = new SmtpClient("smtp.gmail.com", 587);\n    }\n\n    public void SendEmail(string to, string subject, string body)\n    {\n        // منطق الإرسال\n    }\n}\n\npublic class NotificationService\n{\n    private EmailService _emailService;\n\n    public NotificationService()\n    {\n        _emailService = new EmailService(); // ارتباط صارم\n    }\n\n    public void NotifyUser(string email)\n    {\n        _emailService.SendEmail(email, "إشعار", "مرحبًا!");\n    }\n}
\n\n

عيوب هذا الأسلوب:

\n
    \n
  • الارتباط العالي (tight coupling): الفصول NotificationService و EmailService مرتبطة ببعضها البعض بشكل صارم.
  • \n
  • صعوبة الاختبار: من المستحيل استبدال EmailService بكائن وهمي (mock) أثناء اختبارات الوحدة.
  • \n
  • صعوبة التوسع: إذا كنت بحاجة لإضافة إشعارات SMS، فسيتعين عليك تغيير المنطق داخل NotificationService.
  • \n
\n\n

تطبيق حقن التبعيات في C#

\n\n

DI يحل هذه المشكلات باستخدام ثلاثة أساليب رئيسية: الحقن عبر المُنشئ، وعبر الخاصية، وعبر الطريقة. الأكثر شيوعًا والموصى به هو الحقن عبر المُنشئ (Constructor Injection).

\n\n

الخطوة 1. إنشاء واجهة

\n

أولاً، نحدد تجريدًا (واجهة) يصف العقد (contract) لإرسال الرسائل:

\n\n
public interface IMessageSender\n{\n    void Send(string to, string message);\n}
\n\n

الخطوة 2. تطبيق الخدمات المحددة

\n

الآن، سننشئ عدة تطبيقات لهذه الواجهة:

\n\n
public class EmailSender : IMessageSender\n{\n    public void Send(string to, string message)\n    {\n        Console.WriteLine($"إرسال بريد إلكتروني إلى {to}: {message}");\n    }\n}\n\npublic class SmsSender : IMessageSender\n{\n    public void Send(string to, string message)\n    {\n        Console.WriteLine($"إرسال SMS إلى {to}: {message}");\n    }\n}
\n\n

الخطوة 3. تطبيق DI عبر المُنشئ

\n

الآن، الفصل NotificationService لا يقوم بإنشاء التبعيات بنفسه، بل يستقبلها عبر المُنشئ:

\n\n
public class NotificationService\n{\n    private readonly IMessageSender _messageSender;\n\n    // حقن التبعية عبر المُنشئ\n    public NotificationService(IMessageSender messageSender)\n    {\n        _messageSender = messageSender;\n    }\n\n    public void Notify(string userContact, string message)\n    {\n        _messageSender.Send(userContact, message);\n    }\n}
\n\n

الآن يمكننا بسهولة تبديل التطبيقات:

\n\n
// استخدام البريد الإلكتروني\nvar emailSender = new EmailSender();\nvar emailNotifier = new NotificationService(emailSender);\nemailNotifier.Notify("user@example.com", "مرحبًا عبر البريد الإلكتروني!");\n\n// استخدام SMS\nvar sms                

المدونات

توصيات الكتب