سؤال

لقد رأيت البرمجية التالية مرات عديدة:

try
{
    ... // some code
}
catch (Exception ex)
{
    ... // Do something
    throw new CustomException(ex);

    // or
    // throw;

    // or
    // throw ex;
}

هل يمكنك أن تشرح الغرض من إعادة رمي استثناء ؟ هو اتباع نمط/أفضل الممارسات في التعامل مع استثناء?(لقد قرأت في مكان ما أنه يدعى "المتصل أبلغ" النمط؟)

هل كانت مفيدة؟

المحلول

Rethrowing نفس الاستثناء هو مفيد إذا كنت ترغب في, قول, سجل استثناء ، ولكن ليس على التعامل معها.

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

نصائح أخرى

في الواقع هناك فرق بين

throw new CustomException(ex);

و

throw;

والثانية الحفاظ على معلومات مكدس.

ولكن في بعض الأحيان كنت تريد أن تجعل الاستثناء أكثر "ودية" إلى التطبيق الخاص بك المجال بدلا من السماح DatabaseException الوصول إلى واجهة المستخدم الرسومية, سوف يرفع استثناء مخصصة التي تحتوي على استثناء الأصلي.

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

try
{

}
catch (SqlException ex)
{
    switch  (ex.Number) {
        case 17:
        case 4060:
        case 18456:
           throw new InvalidDatabaseConnectionException("The database does not exists or cannot be reached using the supplied connection settings.", ex);
        case 547:
            throw new CouldNotDeleteException("There is a another object still using this object, therefore it cannot be deleted.", ex);
        default:
            throw new UnexpectedDatabaseErrorException("There was an unexpected error from the database.", ex);
    } 
}

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

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

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

عند إنشاء مخصص استثناء, وهنا مرجعية مفيدة:

• العثور على الاسم الحسن الذي ينقل لماذا تم طرح استثناء و تأكد من أن اسم ينتهي مع كلمة "استثناء".

• ضمان تنفيذ ثلاثة معيار الاستثناء المنشئات.

• التأكد من أن لك وضع علامة استثناء مع تسلسل السمة.

• ضمان تنفيذ إلغاء التسلسل منشئ.

• إضافة أي استثناء مخصصة الخصائص التي قد تساعد المطورين على فهم والتعامل مع الاستثناء أفضل.

• إذا قمت بإضافة أي خصائص مخصصة ، تأكد من أنه يمكنك تنفيذ تجاوز GetObjectData إلى تسلسل الخاص بك الخصائص المخصصة.

• إذا قمت بإضافة أي الخصائص المخصصة تجاوز الرسالة الملكية بحيث يمكنك إضافة خصائص إلى مستوى رسالة الاستثناء.

• تذكر أن نعلق استثناء الأصلي باستخدام InnerException الممتلكات الخاصة بك مخصص استثناء.

عادة الصيد إعادة رمي لواحد من سببين ، اعتمادا على حيث رمز يجلس معماريا داخل التطبيق.

في صميم تطبيق عادة الصيد إعادة رمي ترجمة استثناء في شيء أكثر وضوحا.على سبيل المثال إذا كنت تكتب طبقة الوصول إلى البيانات باستخدام رموز الخطأ المخصصة مع SQL Server, قد تترجم SqlException في أشياء مثل ObjectNotFoundException.وهذا مفيد لأن (أ) فإنه يجعل من الأسهل بالنسبة للمتصلين التعامل مع أنواع معينة من استثناء ، و (ب) لأنه يمنع تنفيذ تفاصيل تلك الطبقة مثل حقيقة كنت تستخدم SQL Server على استمرار تتسرب إلى الطبقات الأخرى التي تسمح لك لتغيير الأمور في المستقبل أكثر سهولة.

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

أستطيع أن أفكر في الأسباب التالية:

  • حفظ مجموعة من طرح استثناء أنواع ثابتة ، كجزء من API ، بحيث المتصلين فقط لديك ما يدعو للقلق حول إصلاح مجموعة من الاستثناءات.في جاوة ، أنت عمليا اضطر للقيام بذلك بسبب فحص الاستثناءات آلية.

  • إضافة بعض سياق المعلومات استثناء.على سبيل المثال, بدلا من السماح العارية "سجل" لم يتم العثور على تمرير من خلال من DB ، قد تريد للقبض عليه وإضافة "...أثناء معالجة أمر لا XXX يبحث عن المنتج YYY".

  • القيام ببعض التنظيف - إغلاق الملفات دحر المعاملات ، وتحرير بعض مقابض.

عموما "القيام بشيء ما" إما ينطوي أفضل شرح استثناء (على سبيل المثال ، يلف في استثناء آخر) ، أو تتبع المعلومات من خلال مصادر معينة.

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

هذا لا يعني أن يستخدم أسلوب بحتة أسباب وجيهة ، مرات عديدة يتم استخدامه عندما مطور يعتقد تتبع المعلومات قد تكون هناك حاجة في بعض نقطة في المستقبل ، وفي هذه الحالة تحصل على محاولة {} catch {رمي;} النمط الذي ليس مفيدا على الإطلاق.

أعتقد أن ذلك يعتمد على ما كنت تحاول القيام به مع الاستثناء.

سبب واحد جيد أن سجل الخطأ الأول في الصيد ، ومن ثم رميها إلى واجهة المستخدم لتوليد ودية رسالة خطأ مع خيار رؤية أكثر "تقدما/تفصيلا" عرض الخطأ الذي يحتوي على الخطأ الأصلي.

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

سوف يكون هناك مجموعة من الأسباب الأخرى أن تفعل ذلك على الرغم من.

لمعلوماتك, هذا هو ذات السؤال عن كل نوع من إعادة رمي:اعتبارات الأداء على رمي استثناءات

سؤالي يركز على "لماذا" نحن إعادة رمي الاستثناءات واستخدامه في تطبيق معالجة الاستثناء الاستراتيجية.

حتى بدأت باستخدام EntLib ExceptionBlock, كنت تستخدم لهم سجل الأخطاء قبل رمي لهم.نوع من الحياء عندما كنت أعتقد أنني يمكن أن تعاملت معهم في هذه النقطة, ولكن في ذلك الوقت كان من الأفضل أن يكون لهم الفشل nastily في ضد التعذيب (بعد الدخول بها) بدلا من تغطية التدفق على علة.

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

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

كما رافال ذكر في بعض الأحيان يتم ذلك لتحويل فحص استثناء إلى لحالها استثناء ، أو فحص الاستثناء الذي هو أكثر ملاءمة API.هناك مثال هنا:

http://radio-weblogs.com/0122027/stories/2003/04/01/JavasCheckedExceptionsWereAMistake.html

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

و هذه هي عملية مشتركة في غير استثنائية في العالم.عادة هذا يحدث على الحدود بين اثنين من تطبيق طبقات - عندما وظيفة من طبقة B المكالمات وظيفة من طبقة C, ، فإنه يحول C'النتيجة في B's الداخلية شكل.

A -- calls --> B -- calls --> C

إذا كان لا, ثم في طبقة A الذي يدعو طبقة B سوف يكون هناك مجموعة كاملة من جدك الاستثناءات في التعامل معها.:-)

وكذلك قبول الجواب ، طبقة A قد لا يكون حتى على علم C's استثناء.

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

طبقة, ، بريمج:يسترجع صورة وانها المعلومات الوصفية
طبقة ب, JPEG المكتبة:يجمع المتاحة DCIM العلامات تحليل ملف JPEG
طبقة C, بسيطة DB:فئة قراءة سلسلة السجلات من وصول عشوائي الملف.بعض بايت مكسورة ، لذلك يطرح استثناء قائلا "لا يمكن قراءة UTF-8 سلسلة سجل 'bibliographicCitation'".

لذلك A لن تفهم معنى 'bibliographicCitation'.لذلك B يجب أن يترجم هذا الاستثناء A في TagsReadingException الذي يلتف الأصلي.

السبب الرئيسي من إعادة رمي الاستثناءات هو ترك الاستدعاءات لم يمسها ، حتى تتمكن من الحصول على صورة أكثر اكتمالا من ما يحدث و المكالمات تسلسل.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top