English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

دليل أساسي C#

دليل متقدم C#

C# موجه نحو الكائنات (OOP)

معالجة الاستثناء في C#

في هذا السياق، ستتعلم كيفية معالجة الاستثناءات باستخدام أقسام try،catch وfinally في C#.

يجب معالجة الاستثناءات في التطبيقات لتجنب انهيار البرنامج والنتائج غير المتوقعة، وتسجيل الاستثناءات واستمرار تنفيذ الوظائف الأخرى. يقدم C# دعمًا مدمجًا لمعالجة الاستثناءات باستخدام أقسام try،catch وfinally.

النحو: }}

try
{
    // قد يسبب هذا الكود استثناءً
}
catch
{
    // معالجة الاستثناء هنا
}
finally
{
    // نظافة النهاية
}

block try:يجب أن يوضع أي كود مشبوه قد يسبب استثناءً داخل block try{ }. إذا حدث استثناء أثناء التنفيذ، سيقفز تدفق التحكم إلى أول block catch مطابق.

catch block:block catch هو block معالجة الاستثناءات حيث يمكنك تنفيذ بعض العمليات مثل تسجيل وتحليل الاستثناءات. يستخدم block catch معامل نوع الاستثناء، يمكنك من خلاله الحصول على تفاصيل الاستثناء.

finally block:سيتم تنفيذ block finally دائمًا، سواء تم إثارته استثناءً أم لا. عادةً، يجب استخدام block لتحرير الموارد، مثل إغلاق أي поток أو ملف تم فتحه في block try.

إذا كنت تدخل رمزًا غير رقمي، قد يسبب هذا الاستثناء.

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("أدخل عدد: ");
        var num = int.Parse(Console.ReadLine());
        Console.WriteLine($"مربع {num} هو {num * num}");
    }
}

لمعالجة الاستثناءات المحتملة في المثال السابق، يجب تغليف الكود داخل block try، ثم معالجة الاستثناء في block catch، كما يلي.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("أدخل عدد: ");
            var num = int.parse(Console.ReadLine());
            Console.WriteLine($"مربع {num} هو {num * num}");
        }
        catch
        {
            Console.Write("حدث خطأ.");
        }
        finally
        {
            Console.Write("إعادة المحاولة باستخدام رقم مختلف.");
        }
    }
}

في المثال السابق، سنقوم بتغليف هذا الكود في block try. إذا حدث استثناء داخل block try، فإن البرنامج سيقفز إلى block catch. داخل block catch، سنعرض رسالة لتوضيح معلومات الخطأ للمستخدم، وفي block finally، سنعرض رسالة حول العمليات التي تُنفذ بعد تشغيل البرنامج.

يجب أن يتبع block try أو block catch أو block finally أو جميعها معًا. إذا لم يستخدم block try block catch أو block finally، فإنه سيكون هناك خطأ في التجميع.

في الحالة المثلى، يجب أن يحتوي block catch على معاملات استثناء مدمجة أو مخصصة للحصول على تفاصيل الأخطاء. بما في ذلك معامل type لـ Exception الذي يلتقط جميع أنواع الاستثناءات.

class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.WriteLine("أدخل عدد: ");
            var num = int.parse(Console.ReadLine());
            Console.WriteLine($"مربع {num} هو {num * num}");
        }
        catch(Exception ex)
        {
            Console.Write("معلومات الخطأ: " + ex.Message);
        }
        finally
        {
            Console.Write("إعادة المحاولة باستخدام رقم مختلف.");
        }
    }
}

مرشحات استثناءات

يمكنك استخدام العديد من blocks catch التي تحتوي على استثناءات مختلفة مع catch. يُسمى هذا بـ مرشحات استثناءات. يُعد مرشحات استثناءات مفيدًا عندما تريد معالجة أنواع مختلفة من الاستثناءات بطريقة مختلفة.

class Program
{
    static void Main(string[] args)
    {
        Console.Write("من فضلك أدخل عدد لتقسيم 100: ");
        
        try
        {
            int num = int.Parse(Console.ReadLine());
            int result = 100 / num;
            Console.WriteLine("100 / {0} = {1}", num, result);
        }
        catch(DivideByZeroException ex)
        {
            Console.Write("لا يمكن تقسيمه على الصفر. حاول مرة أخرى.");
        }
        catch(InvalidOperationException ex)
        {
            Console.Write("عمل غير صالح. حاول مرة أخرى.");
        }
        catch(FormatException  ex)
        {
            Console.Write("ليس صيغة صالحة. حاول مرة أخرى.");
        }
        catch(Exception  ex)
        {
            Console.Write("حدث خطأ! حاول مرة أخرى.");
        }
    }
}

في المثال السابق، نحن نصنف العديد من blocks catch التي تحتوي على استثناءات مختلفة. يمكننا عرض رسالة مناسبة للمستخدم بناءً على الخطأ، لذا لن يتكرر الخطأ للمستخدم مرة أخرى.

ملاحظة:
لا يُسمح بوجود أكثر من block catch لنفس نوع الاستثناء. يجب أن يكون block catch الذي يحتوي على نوع استثناء أساسي هو الأخير.

block catch غير صالح

لا يُسمح باستخدام block catch بلاستيجة و block catch مع إضافة Exception في نفس جملة try..catch، لأنهما يفعلان نفس العمل.

try
{
    // كود قد يسبب استثناء
}
catch //لا يمكن أن يكون لديه catch و catch (Exception 异常) في نفس الوقت
{ 
    Console.WriteLine("Exception occurred");
}
catch(Exception ex) //لا يمكن أن يكون لديه catch و catch (Exception 异常) في نفس الوقت
{
    Console.WriteLine("Exception occurred");
}

بالإضافة إلى ذلك، يجب أن يكون بلاستيجة catch {} أو block catch (Exception ex){} هو الأخير. إذا كان هناك block catch آخر بعد block catch {} أو catch (Exception ex)، فإن المترجم سيقوم بإصدار خطأ.

    مثال: catch غير صحيح

try
{
    // كود قد يسبب استثناء
}
catch
{ 
    // يجب أن يكون هذا block catch هو الأخير
}
catch (NullReferenceException nullEx)
{
    Console.WriteLine(nullEx.Message);
}
catch (InvalidCastException inEx)
{
    Console.WriteLine(inEx.Message);
}

block finally

block finally هو block اختياري ويجب أن يكون بعد block try أو catch. سيتم دائمًا تنفيذ block finally، سواء حدث استثناء أم لا. يستخدم block finally عادةً في清理 الكود، مثل التعامل مع الأجهزة غير المدارة.

    مثال: block finally

static void Main(string[] args)
{
    FileInfo file = null;
    try
    {
        Console.Write("أدخل اسم ملف للكتابة: ");
        string fileName = Console.ReadLine();
        file = new FileInfo(fileName);
        file.AppendText("Hello World!")
    }
    catch(Exception ex)
    {
        Console.WriteLine("حدث خطأ: {0}", ex.Message);
    }
    finally
    {
        // هنا يتم تنظيف obj file؛
        file = null;
    }
}
لا يمكن استخدام finally عدة blocks. بالإضافة إلى ذلك، لا يمكن أن يحتوي block finally على كلمات المفتاح return، continue أو break. لا يسمح بإنهاء سيطرة block finally.

try-catch مدمج

يسمح C# باستنساخ blocks try-catch. عند استخدام blocks try-catch المدمجة، يتم استنساخ الاستثناء في block match first try بعد block try الذي يحتوي على catch.

static void Main(string[] args)
{
    var divider = 0;
    try
    {
        try
        {
            var result = 100/divider;
        }
        catch
        {
            Console.WriteLine("catch الداخلية");
        }
    }
    catch
    {
        Console.WriteLine("catch الخارجي");
    }
}
الإخراج:
catch الداخلية

catch في المثال السابق، سيتم تنفيذ block الداخلي لأنه هو أول block catch يعالج جميع أنواع الاستثناءات.

إذا لم يكن هناك أي block catch داخلي يتطابق مع نوع الاستثناء المرفوع، فإن السيطرة ستنتقل إلى block catch الخارجي حتى يتم العثور على محرر استثناء مناسب. انظر المثال التالي.

static void Main(string[] args)
{
    var divider = 0;
    try
    {
        try
        {
            var result = 100/divider;
        }
        catch(NullReferenceException ex)
        {
            Console.WriteLine("catch الداخلية");
        }
    }
    catch
    {
        Console.WriteLine("catch الخارجي");
    }
}
الإخراج:
catch الخارجي

في الأمثلة أعلاه، سيتم إطلاق استثناء نوع DivideByZeroException. نظرًا لأن الكتلة catch الداخلية تتعامل فقط مع NullReferenceTypeException، فإن الكتلة catch الخارجية ستتعامل معها.