अगर मैं एक कोशिश ब्लॉक में एक मूल्य लौटाता हूं तो आखिरकार बयान में आग लग जाएगी?


237

मैं एक दोस्त के लिए कुछ कोड की समीक्षा कर रहा हूं और कहता हूं कि वह कोशिश-अंत में ब्लॉक के अंदर रिटर्न स्टेटमेंट का उपयोग कर रहा था। क्या अंत में खंड में कोड अभी भी आग है, भले ही बाकी की कोशिश ब्लॉक नहीं करता है?

उदाहरण:

public bool someMethod()
{
  try
  {
    return true;
    throw new Exception("test"); // doesn't seem to get executed
  }
  finally
  {
    //code in question
  }
}


यहां संभाले जाने का मतलब है: पकड़ा गया। यहां तक ​​कि आपके वैश्विक हैंडलर में एक खाली कैच ब्लॉक पर्याप्त है। : इसके अलावा, वहाँ अपवाद संभाला नहीं जा सकता हैं StackOverflowException, ExecutionEngineExceptionउन में से कुछ कर रहे हैं। और जब से उन्हें संभाला नहीं जा सकता है, वे finallyनहीं चलेंगे।
हाबिल

8
@ अवि: आप एक अलग स्थिति के बारे में बात कर रहे हैं। यह सवाल एक ब्लॉक में लौटने के बारे में है try। अचानक कार्यक्रम गर्भपात के बारे में कुछ भी नहीं।
जॉन स्कीट

6
@ अविश्वास: मुझे यकीन नहीं है कि "अपवाद के बाद वापसी" से आपका क्या मतलब है, लेकिन यह नहीं लगता कि यहां क्या पूछा जा रहा है। कोड को देखें - tryब्लॉक का पहला स्टेटमेंट एक returnस्टेटमेंट है। (उस ब्लॉक का दूसरा बयान अगम्य है और एक चेतावनी उत्पन्न करेगा।)
जॉन स्कीट

4
@Abel: वास्तव में, और यदि प्रश्न "अंत में कथन में कोड हमेशा हर स्थिति में निष्पादित होता है" होता, जो प्रासंगिक होता। लेकिन वह नहीं पूछा जा रहा था।
जॉन स्कीट

जवाबों:


265

सरल उत्तर: हाँ।


9
@ ईडी: उम, मैं यह नहीं देखता कि बैकग्राउंड थ्रेड्स का इससे क्या लेना-देना है। मूल रूप से, जब तक कि पूरी प्रक्रिया निरस्त नहीं हो जाती, finallyब्लॉक निष्पादित करेगा।
जॉन स्कीट

3
लंबे समय तक जवाब है कि जरूरी नहीं कि आप दौड़ने के लिए अंतत: ब्लॉक हो जाएं, अगर कुछ भयावह हो गया हो, जैसे कि स्टैक ओवरफ्लो, आउट ऑफ मेमोरी अपवाद, किसी तरह का कठिन क्रैश, या अगर कोई आपकी मशीन को सही समय पर अनप्लग कर देता है । लेकिन सभी इरादों और उद्देश्यों के लिए, जब तक आप कुछ बहुत गलत नहीं कर रहे हैं, अंत में हमेशा आग लग जाएगी।
एंड्रयू रोलिंग

यदि किसी कारण से कोशिश करने से पहले कोड विफल हो जाता है तो मैंने देखा है कि अंत में अभी भी निष्पादित होता है। उस स्थिति में आप अंततः के लिए एक शर्त जोड़ सकते हैं जो मानदंडों को पूरा करने के लिए संतुष्ट करता है जब अंत में कोड सफलतापूर्वक निष्पादित होता है
kjosh

200

आम तौर पर, हाँ। अपवाद या वापसी विवरण सहित जो कुछ भी होता है उसे निष्पादित करने के लिए अंत में अनुभाग की गारंटी है। इस नियम का अपवाद थ्रेड ( OutOfMemoryException, StackOverflowException) पर होने वाला एक एसिंक्रोनस अपवाद है ।

Async अपवादों और उस स्थिति में विश्वसनीय कोड के बारे में अधिक जानने के लिए, विवश निष्पादन क्षेत्रों के बारे में पढ़ें ।


154

यहाँ एक छोटी सी परीक्षा है:

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

10
@CodeBlend: यह तब होता है जब WriteLineविधि कॉल के परिणाम के लिए वास्तव में प्रदर्शन किया जाता है। इस मामले में returnकॉल विधियों के परिणाम को सेट करता है, अंत में कंसोल को लिखता है - विधि से बाहर निकलने से पहले। फिर WriteLineमेन मेथड में रिटर्न कॉल से टेक्स्ट को स्पिट करता है।
NotMe

38

MSDN से उद्धरण

अंत में कैसे पूर्ववर्ती की परवाह किए बिना कोड निष्पादित करता है का एक बयान ब्लॉक गारंटी करने के लिए प्रयोग किया जाता है की कोशिश ब्लॉक है से बाहर निकल गया


3
खैर, मेहरदाद के असाधारण मामलों के अलावा, अंत में यह भी नहीं कहा जाएगा कि क्या आप एक कोशिश ब्लॉक में डिबगिंग कर रहे हैं, और फिर डिबगिंग बंद कर दें :)। जीवन में कुछ भी गारंटी नहीं है, ऐसा लगता है।
स्टुअर्टएलसी

1
काफी नहीं, MSDN से उद्धृत : हालांकि, यदि अपवाद नहीं है, तो अंत में ब्लॉक का निष्पादन इस बात पर निर्भर करता है कि अपवाद के ऑपरेशन को कैसे ट्रिगर किया जाता है। बदले में, यह निर्भर करता है कि आपका कंप्यूटर कैसे सेट किया गया है।
हाबिल

1
@Abel यहाँ एक महत्वपूर्ण बिंदु बनाता है। हर कोई यह देख सकता है कि यदि कार्य प्रबंधक के माध्यम से कार्यक्रम को रद्द कर दिया गया है तो आखिरकार ब्लॉक को कैसे निष्पादित नहीं किया जाता है। लेकिन यह जवाब है, जैसा कि यह खड़ा है, सादा गलत: finallyवास्तव में पूरी तरह से सामान्य कार्यक्रमों के लिए भी कुछ नहीं की गारंटी देता है (जो इस अपवाद को फेंकने के लिए हुआ)।
पीटर -

19

आम तौर पर हाँ, अंत में चलेगा।

निम्नलिखित तीन परिदृश्यों के लिए, अंत में हमेशा चलेंगे:

  1. कोई अपवाद नहीं होता है
  2. तुल्यकालिक अपवाद (सामान्य प्रोग्राम प्रवाह में होने वाले अपवाद)।
    इसमें सीएलएस अपवाद अपवाद शामिल हैं जो सिस्टम से प्राप्त होते हैं। अपवाद और गैर-सीएलएस अपवाद अपवाद हैं, जो सिस्टम से उत्पन्न नहीं होते हैं। अपवाद। गैर-सीएलएस अपवाद अपवाद स्वचालित रूप से RuntimeWrappedException द्वारा लपेटे जाते हैं। C # गैर-CLS शिकायत अपवादों को नहीं फेंक सकता है, लेकिन C ++ जैसी भाषाएं कर सकता है। C # को ऐसी भाषा में लिखे गए कोड में कॉल किया जा सकता है जो गैर-सीएलएस अनुपालन अपवादों को फेंक सकता है।
  3. अतुल्यकालिक ThreadAbortException
    .NET 2.0 के रूप में, एक ThreadAbortException अब अंत में चलने से नहीं रोकेगा। अब पहले या बाद में ThreadAbortException को फहराया जाता है। अंत में हमेशा चलेगा और एक थ्रेड एबॉर्ट द्वारा बाधित नहीं होगा, इसलिए जब तक थ्रेड एबॉर्ट होने से पहले वास्तव में कोशिश की गई थी।

निम्नलिखित परिदृश्य, अंत में नहीं चलेगा:

अतुल्यकालिक StackOverflowException।
.NET 2.0 के रूप में एक स्टैक ओवरफ्लो प्रक्रिया को समाप्त करने का कारण होगा। अंत में नहीं चलाया जाएगा, जब तक कि अंत में एक सीईआर (विवश निष्पादन क्षेत्र) बनाने के लिए एक और बाधा नहीं लागू होती है। CER का उपयोग सामान्य उपयोगकर्ता कोड में नहीं किया जाना चाहिए। उन्हें केवल उसी स्थान पर उपयोग किया जाना चाहिए जहां यह महत्वपूर्ण है कि क्लीन-अप कोड हमेशा चलता है - सभी प्रक्रिया वैसे भी स्टैक ओवरफ्लो पर बंद हो रही है और इसलिए सभी प्रबंधित ऑब्जेक्ट डिफ़ॉल्ट रूप से साफ हो जाएंगे। इस प्रकार, केवल एक सीईआर प्रासंगिक होना चाहिए जो संसाधनों के लिए है जो प्रक्रिया से बाहर आवंटित किए गए हैं, जैसे, अप्रबंधित हैंडल।

आमतौर पर, अप्रबंधित कोड को उपयोगकर्ता कोड द्वारा उपभोग किए जाने से पहले कुछ प्रबंधित वर्ग द्वारा लपेटा जाता है। प्रबंधित आवरण वर्ग आम तौर पर अप्रबंधित हैंडल को लपेटने के लिए एक SafeHandle का उपयोग करेगा। सेफहैंडल एक महत्वपूर्ण अंतिम उपकरण और एक रिलीज विधि को लागू करता है जो सफाई कोड के निष्पादन की गारंटी देने के लिए एक सीईआर में चलाया जाता है। इस कारण से, आपको CERs को आउट-आउट उपयोगकर्ता कोड के साथ नहीं देखना चाहिए।

इसलिए तथ्य यह है कि अंत में StackOverflowException पर नहीं चलता है उपयोगकर्ता कोड पर कोई प्रभाव नहीं होना चाहिए, क्योंकि प्रक्रिया वैसे भी समाप्त हो जाएगी। यदि आपके पास कुछ किनारे का मामला है, जहां आपको कुछ अप्रबंधित संसाधन को साफ करने की आवश्यकता है, तो सुरक्षित हैण्डल या क्रिटिकलफाइनलऑब्जेक्ट के बाहर, तो निम्नानुसार एक सीईआर का उपयोग करें; लेकिन कृपया ध्यान दें, यह बुरा अभ्यास है - अप्रबंधित अवधारणा को एक प्रबंधित वर्ग (तों) और डिजाइन द्वारा उपयुक्त सेफहैंडल (ओं) में सारगर्भित किया जाना चाहिए।

जैसे,

// 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.
}

कृपया ध्यान दें कि SOE के मामले में भी CER नहीं चलेगा। जिस समय आपने इसे लिखा था, सीईआर पर MSDN प्रलेखन गलत / अपूर्ण था। एक SOE FailFastआंतरिक रूप से ट्रिगर होगा । जिस तरह से मैं उन लोगों को पकड़ने में कामयाब रहा, वह सीएलआर रनटाइम होस्टिंग को अनुकूलित करके है । ध्यान दें कि आपका बिंदु अभी भी कुछ अन्य अतुल्यकालिक अपवादों के लिए मान्य है।
हाबिल

10

इसका एक बहुत महत्वपूर्ण अपवाद है जिसे मैंने किसी भी अन्य उत्तर में नहीं देखा है, और जो (18 साल से सी # में प्रोग्रामिंग के बाद) मुझे विश्वास नहीं हो रहा है कि मुझे नहीं पता था।

यदि आप अपने ब्लॉक के अंदर किसी भी प्रकार के अपवाद को फेंकते हैं या ट्रिगर करते हैं catch(न कि केवल अजीब StackOverflowExceptionsऔर उस ilk की चीजें), और आपके पास 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();
}

मुझे यकीन है कि इसके लिए एक कारण है, लेकिन यह विचित्र है कि यह अधिक व्यापक रूप से ज्ञात नहीं है। (यह उदाहरण के लिए यहां नोट किया गया है , लेकिन इस विशेष प्रश्न में कहीं भी नहीं।)


खैर, finallyब्लॉक बस ब्लॉक के लिए एक पकड़ नहीं है catch
पीटर -

7

मुझे लगता है कि मुझे पार्टी में देर हो रही है, लेकिन परिदृश्य में (ओपी के उदाहरण से अलग) जहां वास्तव में एक अपवाद MSDN राज्यों ( https://msdn.microsoft.com/en-us/library/zwc8s4fz.aspx ) को फेंक दिया गया है : "यदि अपवाद नहीं पकड़ा गया है, तो अंत में ब्लॉक का निष्पादन इस बात पर निर्भर करता है कि ऑपरेटिंग सिस्टम अपवाद के लिए ऑपरेशन को ट्रिगर करना चुनता है या नहीं।"

अंत में ब्लॉक को केवल निष्पादित करने की गारंटी दी जाती है यदि कुछ अन्य फ़ंक्शन (जैसे कि मेन) कॉल स्टैक को आगे छोड़ता है और अपवाद को पकड़ता है। यह विवरण आम तौर पर एक समस्या नहीं है क्योंकि सभी रन समय वातावरण (सीएलआर और ओएस) सी # प्रोग्राम नि: शुल्क अधिकांश संसाधनों पर चलते हैं जो एक प्रक्रिया का मालिक है जब यह बाहर निकलता है (फ़ाइल हैंडल आदि)। कुछ मामलों में यह महत्वपूर्ण हो सकता है: एक डेटाबेस ऑपरेशन आधा चल रहा है जिसे आप सम्मान देना चाहते हैं। खोलना; या कुछ दूरस्थ कनेक्शन जो ओएस द्वारा स्वचालित रूप से बंद नहीं किए जा सकते हैं और फिर एक सर्वर को ब्लॉक करते हैं।


3

हाँ। यह वास्तव में है कि आखिरकार बयान का मुख्य बिंदु। जब तक कुछ कैटेस्ट्रॉफिक नहीं होता है (स्मृति से बाहर, कंप्यूटर अनप्लग्ड, आदि) आखिरकार बयान को हमेशा निष्पादित किया जाना चाहिए।


1
मैं असहमत हूं। सी एफ मेरा जवाब। कोशिश ब्लॉक में एक पूरी तरह से सामान्य अपवाद ब्लॉक को बायपास करने के लिए पर्याप्त है finallyअगर उस अपवाद को कभी नहीं पकड़ा जाता है। कि मुझे आश्चर्य से पकड़ा; ;-)
पीटर -

@ पीटरए. श्नाइडर - यह दिलचस्प है। बेशक, इसके निहितार्थ वास्तव में बहुत अधिक नहीं बदलते हैं। यदि कॉल स्टैक अप कुछ भी अपवाद को पकड़ने वाला नहीं है, तो इसका मतलब यह होना चाहिए (अगर मैं सही तरीके से समझता हूं) कि प्रक्रिया समाप्त होने वाली है। तो यह खींचने वाली स्थिति के समान है। मुझे लगता है कि इस से takeaway यह है कि आपको हमेशा एक शीर्ष-स्तर या अखंडित-अपवाद को पकड़ना चाहिए।
जेफरी एल व्हाइटलेज

वास्तव में, यही मैं भी समझता हूं। मुझे वह आश्चर्यजनक लगी। सच: सबसे आम संसाधन स्वचालित रूप से जारी किए जाएंगे, विशेष रूप से मेमोरी और खोली गई फ़ाइलों में। लेकिन ओएस के बारे में संसाधनों को पता नहीं है - एक उदाहरण के रूप में खुले सर्वर या डेटाबेस कनेक्शन - दूरस्थ तरफ खुले रह सकते हैं क्योंकि वे कभी ठीक से बंद नहीं हुए हैं; सॉकेट्स लिंचिंग आदि करते रहते हैं, मुझे लगता है कि शीर्ष स्तर के अपवाद हैंडलर का होना समझदारी है, हां।
पीटर -


2

यदि आप System.exit (0) का उपयोग कर आवेदन से बाहर निकल रहे हैं तो अंत में अभ्यस्त न हों; जैसे की

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

परिणाम सिर्फ होगा: प्रयास करें


4
आप गलत भाषा में जवाब दे रहे हैं जो मुझे लगता है, सवाल के बारे में था c#, लेकिन ऐसा लगता है Java। और इसके अलावा, ज्यादातर मामलों System.exit()में एक बुरा डिजाइन का एक संकेत है :-)
z00l

0

99% परिदृश्यों की यह गारंटी होगी कि finallyब्लॉक के अंदर का कोड चलेगा, हालाँकि, इस परिदृश्य के बारे में सोचें: आपके पास एक थ्रेड है जिसमें try-> finallyब्लॉक (नहीं catch) है और आपको उस थ्रेड के भीतर एक अखंड अपवाद मिलता है। इस स्थिति में, थ्रेड बाहर निकल जाएगा और इसके finallyब्लॉक को निष्पादित नहीं किया जाएगा (इस मामले में आवेदन जारी रह सकता है)

यह परिदृश्य बहुत दुर्लभ है, लेकिन यह केवल यह दिखाने के लिए है कि इसका उत्तर हमेशा "हां" नहीं है, यह ज्यादातर समय "हां" और कभी-कभी, दुर्लभ परिस्थितियों में, "नहीं" है।


0

अंत में ब्लॉक का मुख्य उद्देश्य इसके अंदर जो कुछ भी लिखा गया है उसे निष्पादित करना है। यह कोशिश या कैच में जो कुछ भी होता है, उस पर निर्भर नहीं होना चाहिए। कभी भी System.Environment.Exit (1) के साथ आवेदन कोड की अगली पंक्ति में जाने के बिना बाहर निकल जाएगा।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.