حقن التبعيات (Dependency Injection) في C#: دليل شامل

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

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

ابدأ الدورة
```html

ما هو Dependency Injection في C# ولماذا هو مطلوب



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



الهدف الرئيسي لـ DI هو تطبيق مبدأ Inversion of Control (IoC)، حيث يتم نقل التحكم في إنشاء الكائنات إلى حاوية خارجية أو إطار عمل. هذا يغير بشكل جذري بنية التطبيق، مما يجعله مرنًا وجاهزًا للتغييرات.



مشكلة الاقتران القوي (Tight Coupling)



لننظر إلى مثال نموذجي بدون DI:



public class OrderService{    private readonly EmailSender _emailSender;

public OrderService() { // اعتماد قوي — إنشاء نسخة من كلاس محدد _emailSender = new EmailSender(); }

public void ProcessOrder(Order order) { // منطق معالجة الطلب _emailSender.Send("تمت معالجة الطلب"); }}


هنا OrderService يعتمد بشكل مباشر على EmailSender. إذا أردنا استبدال إرسال البريد الإلكتروني بـ SMS أو تسجيل، فسنضطر لتعديل كود OrderService. هذا ينتهك مبدأ Open/Closed ويجعل الاختبار الوحدوي شبه مستحيل.



الطرق الرئيسية لحقن التبعيات في C#



في C#، هناك ثلاث طرق رئيسية لتطبيق DI. كل منها له سيناريوهات استخدامه وخصائصه.



1. الحقن عبر المُنشئ (Constructor Injection)



هذه هي الطريقة الأكثر شيوعًا والموصى بها في .NET. يتم تمرير التبعيات عبر باراميترات المُنشئ وعادةً ما تُحفظ في حقول خاصة للقراءة فقط (readonly).



public interface INotificationService{    void Send(string message);}

public class EmailService : INotificationService{ public void Send(string message) { Console.WriteLine($"تم إرسال البريد الإلكتروني: {message}"); }}

public class OrderService{ private readonly INotificationService _notificationService;

// يتم حقن التبعية عبر المُنشئ public OrderService(INotificationService notificationService) { _notificationService = notificationService; }

public void ProcessOrder(Order order) { // منطق... _notificationService.Send("تمت معالجة الطلب"); }}


المزايا: يظهر بوضوح ما هي التبعيات التي يحتاجها الكلاس؛ التبعيات غير قابلة للتغيير بعد إنشاء الكائن؛ سهولة الاختبار عن طريق توفير كائنات mock.



2. الحقن عبر الخاصية (Property Injection)



يتم تعيين التبعية عبر خاصية عامة (setter). يُستخدم بشكل أقل عندما لا تكون التبعية إلزامية لعمل الكلاس.



public class OrderService{    public INotificationService NotificationService { get; set; }

public OrderService() { }

public void ProcessOrder(Order order) { if (NotificationService != null) { NotificationService.Send("تمت معالجة الطلب"); } }}


العيب: يمكن نسيان تعيين التبعية، مما يؤدي إلى NullReferenceException أثناء التنفيذ. يُوصى باستخدامه فقط للتبعيات الاختيارية.



3. الحقن عبر الطريقة (Method Injection)



يتم تمرير التبعية مباشرة إلى الطريقة التي تُستخدم فيها. هذا مناسب عندما تكون التبعية مطلوبة فقط لإجراء معين واحد.



public class OrderService{    public void ProcessOrder(Order order, INotificationService notificationService)    {        // منطق...        notificat
```                

المدونات

توصيات الكتب