في .NET، هل هناك أي ميزة للمحاولة/الالتقاط حيث يتم إعادة الالتقاط فقط [نسخة مكررة]

StackOverflow https://stackoverflow.com/questions/1207172

  •  05-07-2019
  •  | 
  •  

سؤال

التكرار المحتمل:
لماذا قبض على الاستثناء وإعادة طرحه في C#؟

أواجه أحيانًا رمز C# الذي يبدو كالتالي:

        try
        {
            // Some stuff
        }
        catch (Exception e)
        {
            throw e;
        }

أتفهم أنه من الممكن القيام بشيء مثل تسجيل رسالة الاستثناء ثم إعادة طرحها.أنا أتحدث عن المصيد الذي يعيد الاستثناء فقط.لا أرى فائدة من هذا.لدي ثلاثة أسئلة:

1) هل هناك أي فائدة في ذلك؟

2) هل هذا بطيء في تنفيذ الكود على الإطلاق

3) هل سيحدث أي فرق إذا كانت كتلة الالتقاط كما يلي:

        catch (Exception)
        {
            throw;
        }
هل كانت مفيدة؟

المحلول

هذا يعيد بالضبط نفس الاستثناء:

    catch (Exception)
    {
        throw;
    }

حيث أن هذا يعيد الاستثناء دون تتبع المكدس الأصلي:

    catch (Exception e)
    {
        throw e;
    }

غالبا ما يكون هناك سبب وجيه لذلك throw; حيث يمكنك تسجيل الاستثناء أو القيام بأشياء أخرى قبل إعادة الاستثناء.لست على علم بأي أسباب وجيهة لذلك throw e; حيث ستقوم بمسح معلومات تتبع المكدس القيمة.

نصائح أخرى

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

أستخدم هذه التقنية حتى أتمكن من وضع نقطة توقف عند التصحيح.وأحيانا أزيله بعد الانتهاء..

يتمثل الاختلاف الرئيسي في أنه سيتم تغيير تتبع المكدس الخاص بالاستثناء لإظهار أنه نشأ من موقع محاولة الالتقاط في المثال الأول.

يحتفظ المثال الثاني بتتبع المكدس.

هل هناك ميزة

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

هل يبطئ الكود على الإطلاق

على الاطلاق؟ربما.إبطائه بأي فرق قابل للقياس؟لا.

هل سيحدث أي فرق إذا كانت كتلة الالتقاط على النحو التالي؟

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

1- لا أرى أي فائدة على الإطلاق.إذا كنت لا تتعامل مع الاستثناء، فاترك المحاولة/الالتقاط.المشكلة الأخرى في هذا المثال هي أنك لا تطرح الاستثناء الفعلي، بل استثناءً جديدًا.

2 - نعم - ولكن ما لم يكن هذا موجودًا في حلقة كبيرة من التعليمات البرمجية المتكررة، فمن المحتمل أنك لن تلاحظ فرقًا.

3 - نعم.في المثال الأول، أنت تعبث بمكدس الاستدعاءات الخاص بك.يحافظ هذا المثال على المكدس سليمًا عن طريق ظهور الاستثناء، بدلاً من طرح استثناء جديد.

إذا كنت لا تفعل شيئًا آخر حقًا، فهناك ميزة واحدة فقط وجدتها على الإطلاق:يمكنك وضع نقطة توقف على throw خط.إنه يجعلها محددة للغاية (بدلاً من مجرد الانفصال عند طرح نوع الاستثناء هذا).

سأفعل ذلك فقط أثناء تصحيح الأخطاء، ثم أرجع الرمز مرة أخرى.

لقد كتبت اختبارًا سريعًا لإظهار الاختلافات.هنا هو رمز الاختبار:

try
{
    var broken = int.Parse("null");
}
catch (Exception ex1)
{
    System.Diagnostics.Trace.WriteLine(ex1.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception)
    {
        throw;
    }
}
catch (Exception ex2)
{
    System.Diagnostics.Trace.WriteLine(ex2.ToString());
}

try
{
    try
    {
        var broken = int.Parse("null");
    }
    catch (Exception ex3)
    {
        throw ex3;
    }
}
catch (Exception ex4)
{
    System.Diagnostics.Trace.WriteLine(ex4.ToString());
}

بتشغيل هذا، أحصل على الإخراج التالي:

A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 18
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Int32.Parse(String s)
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 33
A first chance exception of type 'System.FormatException' occurred in mscorlib.dll
A first chance exception of type 'System.FormatException' occurred in QuickTests.exe
System.FormatException: Input string was not in a correct format.
   at QuickTests.Program.Main(String[] args) in C:\Projects\Test\QuickTests\Program.cs:line 49

ستلاحظ أن الاستثناءين الأولين يعملان بنفس الطريقة.لكن "رمي ex3 ؛" يؤدي إلى اختلاف الاستثناء المبلغ عنه ، مما يغير تتبع المكدس للاستثناء.

غالبًا ما يكون لطيفًا للتسجيل.وأيضًا إذا تركت الوسيطة في إعادة الرمي، فلن يغير ذلك تتبع المكدس لـ e.

في بعض الأحيان تريد السماح بأنواع معينة على سبيل المثال.إليك معالجة خاصة لكل شيء ما عدا FooException:

try
{
    // ...
}
catch (FooException)
{
    throw;
}
catch (Exception ex)
{
    // handle differently, like wrap with a FooException
    throw new FooException("I pitty the Foo.", ex);
}

بالتأكيد.

غالبًا ما تريد تسجيل الاستثناء قبل طرحه، وربما تسجيل بعض القيم المتغيرة من الطريقة.

ومع ذلك، فإن مجرد الإمساك به لرميه لا يكسبك الكثير.

تماما مثل ذلك، لا.ومع ذلك، قد ترغب في القيام بذلك:

catch (Exception ex)
{
     LogException(ex);
     throw;
}

حيث LogException() عبارة عن فئة مخصصة تقوم بتسجيل الاستثناء أو إرسال تنبيه عبر البريد الإلكتروني أو شيء من هذا القبيل.

أعتقد أن الهدف هو التأكد من طرح نوع واحد فقط من الاستثناءات.إنها IMHO سيئة جدًا لمكافحة النمط

على سبيل المثال

try
{
    throw XYZ();
}
catch(Exception e)
{
    throw e;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top