Menu
Coddy logo textTech
flag Ar iconالعربيةdown icon

واجهة IDisposable وجملة using

جزء من قسم Object Oriented Programming في رحلة C# على Coddy — الدرس 45 من 70.

تحتفظ بعض الكائنات بموارد لا يستطيع جامع المهملات (garbage collector) تنظيفها تلقائيًا - مثل مقابض الملفات، واتصالات قواعد البيانات، ومقابس الشبكة. توفر واجهة IDisposable طريقة قياسية لتحرير هذه الموارد عند الانتهاء من استخدامها.

تقوم الفئة بتنفيذ IDisposable من خلال توفير دالة Dispose():

public class FileHandler : IDisposable
{
    private bool disposed = false;
    
    public void Dispose()
    {
        if (!disposed)
        {
            Console.WriteLine("Releasing resources...");
            disposed = true;
        }
    }
}

يمكنك استدعاء Dispose() يدوياً، ولكن ماذا لو حدث استثناء قبل أن تصل إلى ذلك السطر؟ تضمن عبارة using حدوث عملية التنظيف، حتى عندما تسوء الأمور:

using (FileHandler handler = new FileHandler())
{
    // العمل مع المعالج
}  // يتم استدعاء Dispose() تلقائياً هنا

توفر لغة C# الحديثة بناء جملة أكثر بساطة مع تصريح using، والذي يقوم بالتخلص من الكائن عندما يخرج عن النطاق:

void ProcessFile()
{
    using FileHandler handler = new FileHandler();
    // التعامل مع handler
}  // يتم استدعاء Dispose() عند الخروج من الدالة

تعمل جملة using مع أي نوع يقوم بتنفيذ IDisposable. الفئات المضمنة مثل StreamReader و SqlConnection و HttpClient جميعها تقوم بتنفيذ هذه الواجهة، مما يجعل إدارة الموارد بشكل صحيح أمراً سهلاً وموثوقاً.

challenge icon

التحدي

سهل

لنقم ببناء محاكي لاتصال قاعدة بيانات يوضح الإدارة السليمة للموارد باستخدام واجهة IDisposable وعبارة using. ستقوم بإنشاء فئة تتتبع وقت فتح وإغلاق الاتصالات، مما يضمن تحرير الموارد دائماً بشكل صحيح.

ستقوم بتنظيم الكود الخاص بك عبر ملفين:

  • DatabaseConnection.cs: أنشئ فئة DatabaseConnection في مساحة الأسماء DataAccess التي تنفذ IDisposable. يجب أن يقوم الاتصال الخاص بك بـ:
    • امتلاك خاصية ConnectionName (سلسلة نصية، للقراءة فقط) يتم تعيينها من خلال المنشئ (constructor)
    • تتبع ما إذا كان قد تم التخلص من الاتصال (disposed) باستخدام حقل منطقي (boolean) خاص
    • طباعة Connection opened: {ConnectionName} عند إنشاء الكائن (في المنشئ)
    • تنفيذ طريقة Dispose() لطباعة Connection closed: {ConnectionName} - ولكن فقط إذا لم يتم التخلص منه بالفعل (لمنع التخلص المزدوج)
    • امتلاك طريقة Query(string sql) تعيد Executing on {ConnectionName}: {sql}
  • Program.cs: في ملفك الرئيسي، وضح الإدارة السليمة للموارد باستخدام عبارة using مع اتصال قاعدة البيانات الخاص بك. أنشئ اتصالاً، ونفذ استعلاماً، واترك كتلة using تتعامل مع عملية التنظيف تلقائياً.

ستتلقى مدخلين:

  • اسم الاتصال (على سبيل المثال، MainDB)
  • استعلام SQL المراد تنفيذه (على سبيل المثال، SELECT * FROM Users)

استخدم عبارة using لإنشاء اتصالك. داخل الكتلة، استدعِ طريقة Query واطبع نتيجتها. عندما تنتهي كتلة using، سيتم استدعاء Dispose() تلقائياً.

على سبيل المثال، إذا كانت المدخلات هي MainDB و SELECT * FROM Users، يجب أن يكون المخرج:

Connection opened: MainDB
Executing on MainDB: SELECT * FROM Users
Connection closed: MainDB

لاحظ كيف يتم إغلاق الاتصال تلقائياً عند انتهاء كتلة using - لن تضطر أبداً إلى تذكر استدعاء Dispose() يدوياً. يضمن هذا النمط تنظيف الموارد دائماً، حتى في حالة حدوث استثناء داخل الكتلة!

ورقة مرجعية

توفر واجهة IDisposable طريقة قياسية لتحرير الموارد التي لا يستطيع جامع المهملات (garbage collector) تنظيفها تلقائيًا (مقابض الملفات، اتصالات قاعدة البيانات، ومقابس الشبكة).

تقوم الفئة بتنفيذ IDisposable من خلال توفير طريقة Dispose():

public class FileHandler : IDisposable
{
    private bool disposed = false;
    
    public void Dispose()
    {
        if (!disposed)
        {
            Console.WriteLine("Releasing resources...");
            disposed = true;
        }
    }
}

تضمن عبارة using حدوث عملية التنظيف تلقائيًا، حتى عند حدوث استثناءات:

using (FileHandler handler = new FileHandler())
{
    // العمل مع المعالج
}  // يتم استدعاء Dispose() تلقائيًا هنا

توفر لغة C# الحديثة بناء جملة أكثر نظافة مع تصريح using:

void ProcessFile()
{
    using FileHandler handler = new FileHandler();
    // العمل مع المعالج
}  // يتم استدعاء Dispose() عند الخروج من الطريقة

تعمل عبارة using مع أي نوع يقوم بتنفيذ IDisposable، بما في ذلك الفئات المضمنة مثل StreamReader و SqlConnection و HttpClient.

جرّب بنفسك

using System;
using DataAccess;

class Program
{
    public static void Main(string[] args)
    {
        string connectionName = Console.ReadLine();
        string sqlQuery = Console.ReadLine();
        
        // TODO: استخدم عبارة 'using' لإنشاء DatabaseConnection
        // داخل كتلة using:
        // 1. استدعِ التابع Query مع sqlQuery
        // 2. اطبع نتيجة التابع Query
        // سيتم استدعاء التابع Dispose تلقائياً عند انتهاء كتلة using
        
    }
}
quiz iconاختبر نفسك

يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.

جميع دروس Object Oriented Programming