معالجة الأخطاء في C#: try/catch والمزيد
معالجة الأخطاء هي أحد المكونات الأساسية للبرامج الموثوقة. في C#، يتم استخدام آلية الاستثناءات (exceptions) لهذا الغرض. الاستخدام الصحيح لبنى try و catch و finally لا يسمح فقط بتجنب الإنهاء المفاجئ للبرنامج، بل يجعل الكود أكثر قابلية للقراءة والتوقع. في هذه المقالة، سنستعرض أساسيات معالجة الاستثناءات وأفضل الممارسات والإمكانيات المتقدمة التي توفرها منصة .NET.
1. الكتلة الأساسية try/catch/finally
الأداة الرئيسية لمعالجة الأخطاء في C# هي الكتلة try-catch-finally. تركيبها بديهي:
- try — تحتوي على الكود الذي قد يرمي استثناءً.
- catch — تلتقط الاستثناء وتعالجه.
- finally — تُنفذ دائمًا، بغض النظر عن وجود استثناء. تُستخدم لتحرير الموارد (إغلاق الملفات، اتصالات قاعدة البيانات).
لننظر إلى مثال بسيط — القسمة على صفر:
using System;
class Program{ static void Main() { try { int a = 10; int b = 0; int result = a / b; // هنا سيحدث استثناء Console.WriteLine($"النتيجة: {result}"); } catch (DivideByZeroException ex) { Console.WriteLine($"خطأ: {ex.Message}"); } finally { Console.WriteLine("تم تنفيذ كتلة finally."); } }}مخرجات البرنامج:
خطأ: محاولة القسمة على صفر.تم تنفيذ كتلة finally.لاحظ: إذا لم تحدد نوعًا معينًا للاستثناء، فإن كتلة catch ستلتقط جميع الاستثناءات. قد يكون هذا مناسبًا، لكنه غالبًا ما يُعتبر ممارسة سيئة لأنه يخفي المشكلات الحقيقية.
2. أنواع الاستثناءات وتسلسلها الهرمي
في C#، جميع الاستثناءات ترث من الفئة الأساسية System.Exception. الأكثر استخدامًا:
SystemException— الفئة الأساسية للاستثناءات النظامية.NullReferenceException— الوصول إلى كائن يساويnull.IndexOutOfRangeException— تجاوز حدود المصفوفة.InvalidOperationException— استدعاء طريقة في حالة غير مسموح بها.ArgumentExceptionومشتقاته (ArgumentNullException،ArgumentOutOfRangeException) — وسائط غير صحيحة للطريقة.
يمكنك التقاط عدة أنواع من الاستثناءات في كتلة catch واحدة (بدءًا من C# 6):
try{ // كود}catch (ArgumentNullException ex) when (ex.ParamName == "userId"){ Console.WriteLine("الوسيط userId يجب ألا يكون null.");}catch (InvalidOperationException ex){ Console.WriteLine($"عملية غير صحيحة: {ex.Message}");}catch (Exception ex) when (Log(ex, "خطأ غير معروف")){ // مرشح الاستثناءات — تُنفذ الكتلة فقط إذا كان الشرط صحيحًا throw; // إعادة رمي الاستثناء إلى الأعلى}مرشحات الاستثناءات (الكلمة المفتاحية when) تسمح بإدارة منطق المعالجة بشكل أكثر مرونة دون فقدان مكدس الاستدعاءات.
3. إنشاء استثناءات مخصصة
أحيانًا لا تكون الاستثناءات القياسية كافية. يمكنك إنشاء فئة الاستثناء الخاصة بك عن طريق توريثها من Exception:
public class InvalidAgeException : Exception{ public int Age { get; }
public InvalidAgeException(int age, string message) : base(message) { Age = age; }
public InvalidAgeException(int age, string message, Exception inner) : base(message, inner) { Age = age; }}الآن