هل سيتم تفعيل التعليمات البرمجية الموجودة في العبارة الأخيرة إذا قمت بإرجاع قيمة في كتلة المحاولة؟

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

سؤال

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

مثال:

public bool someMethod()
{
  try
  {
    return true;
    throw new Exception("test"); // doesn't seem to get executed
  }
  finally
  {
    //code in question
  }
}
هل كانت مفيدة؟

المحلول

والجواب بسيط: نعم

نصائح أخرى

وعادة، نعم. مكفول قسم أخيرا لتنفيذ كل ما يحدث بما في ذلك الاستثناءات أو بيان العودة. استثناء لهذه القاعدة استثناء غير متزامن يحدث على موضوع (OutOfMemoryException، StackOverflowException).

لمعرفة المزيد عن استثناءات المتزامن ورمز يمكن الاعتماد عليها في هذا الحالات، قرأت عن <لأ href = "https://blogs.msdn.microsoft.com/bclteam/2005/06/13/constrained-execution-regions-and -اخرى-أخطاء مطبعية-بريان-grunkemeyer / "يختلط =" noreferrer "> المناطق التنفيذ مقيدة .

وهنا اختبار قليلا:

class Class1
{
    [STAThread]
    static void Main(string[] args)
    {
        Console.WriteLine("before");
        Console.WriteLine(test());
        Console.WriteLine("after");
    }

    static string test()
    {
        try
        {
            return "return";
        }
        finally
        {
            Console.WriteLine("finally");
        }
    }
}

والنتيجة هي:

before
finally
return
after

نقلا عن MSDN

أخيراً يتم استخدامه لضمان تنفيذ كتلة بيان من التعليمات البرمجية بغض النظر عن كيفية تنفيذ التعليمات البرمجية السابقة يحاول الكتلة هي خرجت.

عموما نعم، سيتم تشغيل النهاية.

بالنسبة للسيناريوهات الثلاثة التالية، فإن الإرادة النهائية دائماً يجري:

  1. لا تحدث أي استثناءات
  2. الاستثناءات المتزامنة (الاستثناءات التي تحدث في التدفق العادي للبرنامج).
    يتضمن هذا الاستثناءات المتوافقة مع CLS المشتقة من System.Exception والاستثناءات غير المتوافقة مع CLS، والتي لا تشتق من System.Exception.يتم تغليف الاستثناءات غير المتوافقة مع CLS تلقائيًا بواسطة RuntimeWrappedException.لا يمكن لـ C# طرح استثناءات شكوى غير CLS، لكن لغات مثل C++ يمكنها ذلك.من الممكن أن تستدعي لغة C# تعليمات برمجية مكتوبة بلغة يمكنها طرح استثناءات غير متوافقة مع CLS.
  3. ThreadAbortException غير المتزامن
    اعتبارًا من .NET 2.0، لن يمنع ThreadAbortException بعد الآن تشغيل أخيرًا.يتم الآن رفع ThreadAbortException إلى ما قبل أو بعد النهاية.سيتم دائمًا تشغيل المحاولة النهائية دائمًا ولن يتم مقاطعتها بواسطة إحباط مؤشر الترابط، طالما تم إدخال المحاولة بالفعل قبل حدوث إحباط مؤشر الترابط.

السيناريو التالي، لن يتم تشغيل النهاية:

StackOverflowException غير المتزامن.
اعتبارًا من .NET 2.0، سيؤدي تجاوز سعة المكدس إلى إنهاء العملية.لن يتم تشغيل أخيرًا، ما لم يتم تطبيق قيد آخر لجعل CER أخيرًا (منطقة التنفيذ المقيدة).ولا ينبغي استخدام وحدات خفض الانبعاثات المعتمدة في رمز المستخدم العام.يجب استخدامها فقط عندما يكون من الضروري تشغيل تعليمات التنظيف البرمجية دائمًا - بعد إيقاف تشغيل العملية بالكامل عند تجاوز سعة المكدس على أي حال، وبالتالي سيتم تنظيف جميع الكائنات المُدارة بشكل افتراضي.وبالتالي، فإن المكان الوحيد الذي يجب أن تكون فيه وحدات خفض الانبعاثات المعتمدة ذو صلة هو الموارد المخصصة خارج العملية، على سبيل المثال، المقابض غير المُدارة.

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

لذا فإن حقيقة عدم تشغيل أخيرًا على StackOverflowException لن يكون لها أي تأثير على كود المستخدم، نظرًا لأن العملية ستنتهي على أي حال.إذا كانت لديك حالة حافة حيث تحتاج إلى تنظيف بعض الموارد غير المُدارة، خارج SafeHandle أو CriticalFinalizerObject، فاستخدم CER على النحو التالي؛ولكن يرجى ملاحظة أن هذه ممارسة سيئة - يجب تلخيص المفهوم غير المُدار إلى فئة (فئات) مُدارة وSafeHandle (فئات) مناسبة حسب التصميم.

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

// No code can appear after this line, before the try
RuntimeHelpers.PrepareConstrainedRegions();
try
{ 
    // This is *NOT* a CER
}
finally
{
    // This is a CER; guaranteed to run, if the try was entered, 
    // even if a StackOverflowException occurs.
}

هناك استثناء مهم جدًا لهذا والذي لم أره مذكورًا في أي إجابات أخرى، والذي (بعد البرمجة في C# لمدة 18 عامًا) لا أستطيع أن أصدق أنني لم أكن أعرف.

إذا قمت برمي أو تشغيل استثناء لـ أي فرز داخل الخاص بك catch كتلة (ليست غريبة فقط StackOverflowExceptions وأشياء من هذا القبيل)، وليس لديك كامل try/catch/finally كتلة داخل أخرى try/catch كتلة، الخاص بك finally لن يتم تنفيذ الكتلة.يمكن إثبات ذلك بسهولة - وإذا لم أكن قد رأيت ذلك بنفسي، نظرًا لعدد المرات التي قرأت فيها أن حالات الزوايا الصغيرة والغريبة حقًا هي التي يمكن أن تسبب finally منع عدم التنفيذ، لم أكن لأصدق ذلك.

static void Main(string[] args)
{
    Console.WriteLine("Beginning demo of how finally clause doesn't get executed");
    try
    {
        Console.WriteLine("Inside try but before exception.");
        throw new Exception("Exception #1");
    }
    catch (Exception ex)
    {
        Console.WriteLine($"Inside catch for the exception '{ex.Message}' (before throwing another exception).");
        throw;
    }
    finally
    {
        Console.WriteLine("This never gets executed, and that seems very, very wrong.");
    }

    Console.WriteLine("This never gets executed, but I wasn't expecting it to."); 
    Console.ReadLine();
}

أنا متأكد من أن هناك سببًا لذلك، لكن من الغريب أنه غير معروف على نطاق واسع.(انها لوحظ هنا على سبيل المثال، ولكن ليس في أي مكان في هذا السؤال بالذات.)

وأنا أدرك أنا في وقت متأخر إلى الحزب ولكن في السيناريو (يختلف عن المثال OP و) حيث الواقع يتم طرح استثناء الدول MSDN (<لأ href = "https://msdn.microsoft.com/en-us /library/zwc8s4fz.aspx "يختلط =" نوفولو "> https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ): <القوي>" إذا لم يتم القبض على استثناء والتنفيذ كتلة أخيرا يعتمد على ما إذا كان نظام التشغيل يختار لتحريك استثناء يفكوا العملية ".

وكتلة أخيرا هو فقط <م> مضمونة لتنفيذ إذا كان بعض وظيفة أخرى (مثل رئيسي) للأعلى مكدس الاستدعاءات المصيد الاستثناء. هذا التفصيل هو عادة ليست مشكلة لأن كل بيئات وقت التشغيل (CLR وOS) C # برامج تعمل على معظم الموارد المجانية عملية تملك عند خروجها (مؤشرات الملفات وما إلى ذلك). في بعض الحالات قد يكون حاسما على الرغم: عملية قاعدة بيانات نصف الجارية التي تريد ارتكاب التركيب. فك؛ أو بعض اتصال بعيد والتي قد لا تكون مغلقة تلقائيا بواسطة نظام التشغيل ومن ثم كتل الخادم.

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

وكذلك لن إطلاق النار على استثناء uncaught وتعمل في موضوع استضافتها في خدمة ويندوز

أخيرا لا يتم تنفيذ عندما تكون في تشغيل مؤشر ترابط في خدمة ويندوز

وأخيرا متعود تشغيل في حالة إذا كنت الخروج من التطبيق باستخدام System.exit (0)؛ كما هو الحال في

try
{
    System.out.println("try");
    System.exit(0);
}
finally
{
   System.out.println("finally");
}

والنتيجة ستكون فقط: محاولة

و99٪ من السيناريوهات سيكون مضمونا أن التعليمات البرمجية داخل كتلة finally سيتم تشغيل، ومع ذلك، والتفكير في هذا السيناريو: لديك موضوع الذي يحتوي على try-> كتلة finally (لا catch) وتحصل على غير معالج استثناء ضمن هذا الموضوع. في هذه الحالة، فإن موضوع خروج ولن يتم تنفيذ كتلة finally التابعة (تطبيق يمكن أن تستمر في تشغيل في هذه الحالة)

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

والغرض الرئيسي من النهاية كتلة هو تنفيذ كل ما هو مكتوب في داخله. لا ينبغي أن تعتمد على كل ما يحدث في المحاولة أو catch.However مع System.Environment.Exit (1) فإن تطبيق الخروج دون الانتقال إلى السطر التالي من التعليمات البرمجية.

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