معالجة الأخطاء في C#: try/catch والتقنيات المتقدمة لـ .NET

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

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

ابدأ الدورة

معالجة الأخطاء المتقدمة في C#: من try/catch الأساسي إلى الأنماط الصناعية

\n\n

معالجة الأخطاء ليست مجرد حظر للاستثناءات، بل هي فن تصميم أنظمة موثوقة. في C# (.NET)، غالبًا ما يقتصر المطورون على استخدام try/catch، لكن المنصة تقدم آليات أكثر قوة. في هذه المقالة، سنستعرض التقنيات المتقدمة: من مرشحات الاستثناءات إلى أنماط إعادة المحاولة ونقل سياق الخطأ.

\n\n

1. مرشحات الاستثناءات: الدقة بدلاً من الحشو

\n\n

مرشحات الاستثناءات (Exception Filters)، التي ظهرت في C# 6.0، تسمح بتحديد شرط للدخول إلى كتلة catch دون إعادة رمي الاستثناء. هذا أنظف بكثير من النهج التقليدي باستخدام if داخل الكتلة.

\n\n
try\n{\n    // كود قد يرمي استثناءً\n    var result = ProcessData(input);\n}\ncatch (CustomException ex) when (ex.ErrorCode == 1001)\n{\n    // معالجة الأخطاء ذات الرمز 1001 فقط\n    Log.Error($"خطأ حرج: {ex.Message}");\n    throw; // إعادة الرمي إذا لزم الأمر\n}\ncatch (CustomException ex) when (ex.IsRecoverable)\n{\n    // خطأ قابل للاسترداد - نسجله ونواصل\n    Log.Warning($"خطأ قابل للاسترداد: {ex.Message}");\n    RetryOperation();\n}
\n\n

المزايا:

\n
    \n
  • لا حاجة لإعادة throw للتصفية.
  • \n
  • تحسين قابلية القراءة والأداء (لا يتلف مكدس الاستدعاءات).
  • \n
  • يمكن دمج عدة كتل catch بشروط مختلفة.
  • \n
\n\n

2. نمط "إعادة المحاولة" (Retry) وPolly

\n\n

ليست كل الأخطاء قاتلة. للأعطال المؤقتة (مشاكل الشبكة، أقفال قاعدة البيانات)، استخدم نمط إعادة المحاولة. الأدوات المدمجة في C# محدودة، لذا يُوصى باستخدام مكتبة Polly.

\n\n
using Polly;\nusing Polly.Retry;\n\n// تحديد سياسة إعادة المحاولة\nAsyncRetryPolicy retryPolicy = Policy\n    .Handle<HttpRequestException>() // معالجة أخطاء HTTP فقط\n    .WaitAndRetryAsync(\n        3, // عدد المحاولات\n        retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), // تأخير أسي\n        onRetry: (exception, timeSpan, retryCount, context) =>\n        {\n            Log.Warning($"المحاولة {retryCount} فشلت. إعادة المحاولة بعد {timeSpan.Seconds} ثانية.");\n        });\n\n// تطبيق السياسة\nawait retryPolicy.ExecuteAsync(async () =>\n{\n    var response = await httpClient.GetAsync("https://api.example.com/data");\n    response.EnsureSuccessStatusCode();\n});
\n\n

هام: لا تستخدم إعادة محاولة لا نهائية. حدد دائمًا أقصى عدد من المحاولات واستخدم Circuit Breaker لحماية النظام من الأعطال المتتالية.

\n\n

3. النقل الصحيح للاستثناءات: throw مقابل throw ex

\n\n

أحد الأخطاء الأكثر شيوعًا هو فقدان مكدس الاستدعاءات. الفرق بين throw و throw ex حاسم لتصحيح الأخطاء.

\n\n
try\n{\n    // ...\n}\ncatch (Exception ex)\n{\n    // خطأ: نفقد المكدس الأصلي\n    // throw ex;  \n\n    // صحيح: نحتفظ بالمكدس\n    throw;\n\n    // أو: نضيف سياقًا دون فقدان الأصل\n    // throw new ApplicationException("خطأ في الوحدة X", ex);\n}
\n\n

إذا كنت بحاجة لإضافة سياق، استخدم ExceptionDispatchInfo (من مساحة System.Runtime.ExceptionServices) للحفاظ الدقيق على المكدس عند إعادة الرمي بين الخيوط.

\n\n
ExceptionDispatchInfo.Capture(exception).Throw(); // يحتفظ بالمكدس الأصلي
\n\n

4. الاستثناءات المخصصة وسياق الخطأ

\n\n

الاستثناءات القياسية غالبًا لا تحمل سياقًا تجاريًا. أنشئ فئات الاستثناءات الخاصة بك مع خصائص إضافية.

\n\n
public class PaymentProcessingException : Exception\n{\n    public int OrderId { get; }\n    public dec                

المدونات

توصيات الكتب