'अंत' ब्लॉक के अंदर 'जारी' बयान क्यों नहीं हो सकता?


107

मुझे कोई समस्या नहीं है; मैं सिर्फ उत्सुक हूँ। इस परिदृश्य की कल्पना करें:

foreach (var foo in list)
{
    try
    {
         //Some code
    }
    catch (Exception)
    {
        //Some more code
    }
    finally
    {
        continue;
    }
}

यह संकलित नहीं करेगा, क्योंकि यह संकलक त्रुटि CS0157 उठाता है :

नियंत्रण शरीर को अंत में बंद नहीं कर सकता

क्यों?


7
इसलिए। बस उत्सुक। यदि यह आपके लिए पूरी तरह से समझ में आता है कि यह क्यों संकलित नहीं करेगा, तो आप क्यों चाहते हैं कि कोई व्यक्ति यह समझाए कि पहले से क्या समझ में आता है? =)
जे। स्टेन

14
क्यों आप एक की आवश्यकता होगी continue;में finallyब्लॉक? यह ब्लॉक के continue;बाद के रूप में ही नहीं है try -- catch?
बंसी

6
@ J.Steen नहीं, मुझे पता है कि finally/continueC # संकलक की एक सीमा है :-) मैं इस सीमा के कारण पर भी उत्सुक हूं।
xanatos

5
@xanatos - तकनीकी रूप से, यह अंतर्निहित CIL की एक सीमा है। से भाषा कल्पना : "नियंत्रण हस्तांतरण अपवाद संचालन तंत्र के माध्यम से छोड़कर एक पकड़ने हैंडलर या अंत में खंड में प्रवेश की अनुमति कभी नहीं रहा है।" और "एक संरक्षित क्षेत्र से बाहर नियंत्रण हस्तांतरण केवल एक अपवाद निर्देश (छोड़ें, अंत .filter, end.catch, या end.finally) के माध्यम से अनुमति दी है।" brशाखा निर्देशों का परिवार इसे पूरा नहीं कर सकता है।
अनसाइनड

1
@ डिज़ाइन किया गया: यह एक अच्छी सीमा भी है, जिससे यह विचित्र हो जाएगा :)
user7116

जवाबों:


150

finallyब्लॉक चलता है कि कोई अपवाद फेंका गया है या नहीं। यदि एक अपवाद को फेंक दिया जाता है, तो बिल्ली क्या करेगी continue? आप लूप का निष्पादन जारी नहीं रख सकते, क्योंकि एक अनकहा अपवाद किसी अन्य फ़ंक्शन पर नियंत्रण स्थानांतरित कर देगा।

यहां तक ​​कि अगर कोई अपवाद नहीं फेंका जाता है, finallyतब भी चलेगा जब अन्य नियंत्रण हस्तांतरण स्टेटमेंट / कैच ब्लॉक रन के अंदर स्टेटमेंट, जैसे return, उदाहरण के लिए, जो एक ही समस्या लाता है।

संक्षेप में, इसके शब्दार्थ के साथ ब्लॉक के finallyअंदर finallyसे इसके बाहर तक नियंत्रण स्थानांतरित करने की अनुमति देने का कोई मतलब नहीं है।

कुछ वैकल्पिक शब्दार्थों के साथ इसका समर्थन करना सहायक की तुलना में अधिक भ्रामक होगा, क्योंकि ऐसे सरल कार्यपट्टियाँ होती हैं जो इच्छित व्यवहार को स्पष्ट करती हैं। तो आपको एक त्रुटि मिलती है, और आपकी समस्या के बारे में ठीक से सोचने के लिए मजबूर किया जाता है। यह सामान्य "सफलता के गड्ढे में फेंक देता है" विचार है जो सी # में चलता है।

सी #, आप, और सफलता अगर बाहर

यदि आप अपवादों को अनदेखा करना चाहते हैं (अधिक बार नहीं तो यह एक बुरा विचार है) और लूप को निष्पादित करना जारी रखें, सभी ब्लॉक को पकड़ें:

foreach ( var in list )
{
    try{
        //some code
    }catch{
        continue;
    }
}

यदि आप continueकेवल तब ही चाहते हैं जब कोई अपवाद न छोड़ा गया हो, तो बस continueकोशिश-ब्लॉक के बाहर रखें।


12
मैं इसे उत्तर के रूप में स्वीकार करूंगा, क्योंकि आप उन कारणों को समझते हैं जिनके कारण Microsoft ने संभवत: एक अंत में जारी स्वीकार नहीं करने का फैसला किया। संभवतः कि छवियों ने मुझे भी आश्वस्त किया है :)
lpaloub

20
क्या आप "सफलता के गड्ढे में फेंक" विचार को विस्तृत कर सकते हैं? मुझे यह समझ में नहीं आया :-D
Ant


13
छवि जॉन स्कीट, btw द्वारा बनाई गई थी। मुझे यहाँ से मिला: msmvps.com/blogs/jon_skeet/archive/2010/09/02/…
आर। मार्टिनो फर्नांडीस

1
बेशक, एक ब्लॉक continueमें finallyओके ठीक होगा यदि यह केवल finallyब्लॉक के अंदर परिभाषित एक स्थानीय लूप जारी रखता है । हालांकि, प्रश्न में, यह "बाहरी" लूप जारी रखने की कोशिश करता है। इसी तरह के बयान जो आपके पास finallyब्लॉक के अंदर नहीं हो सकते हैं return, break(जब ब्लॉक से बाहर निकल रहे हों) और goto(जब finallyब्लॉक के बाहर लेबल पर जा रहे हों )। संबंधित जावा चर्चा के लिए, जावा में अंतिम ब्लॉक से रिटर्निंग देखें ।
जेपी स्टिग नीलसन

32

यहाँ एक विश्वसनीय स्रोत है:

जारी बयान अंत में ब्लॉक (धारा 8.10) से बाहर नहीं निकल सकता है। जब एक जारी स्टेटमेंट अंत में ब्लॉक के भीतर होता है, तो जारी स्टेटमेंट का लक्ष्य समान रूप से ब्लॉक के भीतर होना चाहिए; अन्यथा, एक संकलन-समय त्रुटि उत्पन्न होती है।

यह MSDN से लिया गया है, 8.9.2 जारी बयान

प्रलेखन का कहना है कि:

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

यह यहाँ से है 8.10 कोशिश बयान


31

आपको लगता है कि यह समझ में आता है, लेकिन यह वास्तव में समझ में नहीं आता है

foreach (var v in List)
{
    try
    {
        //Some code
    }
    catch (Exception)
    {
        //Some more code
        break; or return;
    }
    finally
    {
        continue;
    }
}

क्या आप एक ऐसा करना चाहते हैं को तोड़ने या एक जारी रखने के लिए जब एक अपवाद फेंक दिया जाता है? C # संकलक टीम मानकर breakया अपने हिसाब से निर्णय नहीं लेना चाहती है continue। इसके बजाय, उन्होंने शिकायत करने का फैसला किया कि डेवलपर स्थिति से नियंत्रण स्थानांतरित करने के लिए अस्पष्ट होगा finally block

तो यह डेवलपर का काम है कि वह स्पष्ट रूप से यह बताए कि वह कुछ और मानकर संकलक के बजाय क्या करना चाहता है।

मुझे आशा है कि आप समझ गए होंगे कि यह संकलन क्यों नहीं है!


संबंधित नोट पर, यहां तक ​​कि अगर कोई "कैच" नहीं था, तो एक finallyबयान के बाद निष्पादन पथ प्रभावित होगा कि क्या catchअपवाद के माध्यम से बाहर निकल गया था, और यह कहने का कोई तंत्र नहीं है कि कैसे एक के साथ बातचीत करनी चाहिए continue। हालाँकि मुझे आपका उदाहरण पसंद है, क्योंकि यह एक और भी बड़ी समस्या को दर्शाता है।
सुपरकैट

@supercat आपके साथ सहमत है, मेरा जवाब संकलक के लिए अस्पष्ट स्थिति का एक उदाहरण दिखाता है अभी भी इस दृष्टिकोण के साथ बहुत सारी समस्याएं हैं।
श्रीराम सक्थिवेल

16

जैसा कि दूसरों ने कहा है, लेकिन अपवादों पर ध्यान केंद्रित किया है, यह वास्तव में स्थानांतरण नियंत्रण के अस्पष्ट हैंडलिंग के बारे में है।

आपके दिमाग में, आप शायद इस तरह से एक परिदृश्य के बारे में सोच रहे हैं:

public static object SafeMethod()
{
    foreach(var item in list)
    {
        try
        {
            try
            {
                //do something that won't transfer control outside
            }
            catch
            {
                //catch everything to not throw exceptions
            }
        }
        finally
        {
            if (someCondition)
                //no exception will be thrown, 
                //so theoretically this could work
                continue;
        }
    }

    return someValue;
}

सैद्धांतिक रूप से, आप नियंत्रण प्रवाह को ट्रैक कर सकते हैं और कह सकते हैं, हां, यह "ठीक" है। कोई अपवाद नहीं फेंका गया है, कोई नियंत्रण स्थानांतरित नहीं किया गया है। लेकिन सी # भाषा डिजाइनरों के दिमाग में अन्य मुद्दे थे।

फेंकता अपवाद

public static void Exception()
{
    try
    {
        foreach(var item in list)
        {
            try
            {
                throw new Exception("What now?");
            }
            finally
            {
                continue;
            }
        }
    }
    catch
    {
        //do I get hit?
    }
}

खूंखार गोटो

public static void Goto()
{
    foreach(var item in list)
    {
        try
        {
            goto pigsfly;
        }
        finally
        {
            continue;
        }
    }

    pigsfly:
}

वापसी

public static object ReturnSomething()
{
    foreach(var item in list)
    {
        try
        {
            return item;
        }
        finally
        {
            continue;
        }
    }
}

संबंध विच्छेद

public static void Break()
{
    foreach(var item in list)
    {
        try
        {
            break;
        }
        finally
        {
            continue;
        }
    }
}

तो अंत में, हाँ, जबकि वहाँ है एक मामूली एक उपयोग करने की संभावना continueस्थितियों में, जहां नियंत्रण स्थानांतरित नहीं किया जा रहा है, लेकिन एक अच्छा सौदा मामलों की (बहुमत?) अपवादों या शामिल returnब्लॉकों। भाषा डिजाइनरों ने महसूस किया कि यह बहुत अस्पष्ट होगा और (संभावना) यह सुनिश्चित करना असंभव होगा कि आपका continueउपयोग केवल उन मामलों में किया जाए जहां नियंत्रण प्रवाह स्थानांतरित नहीं हो रहा है।


जब प्रोबेशन क्रैश हो रहा था, तब जावा में भी यही स्थिति थी। आपकी व्याख्या बहुत अच्छी है। C # संकलन समय त्रुटि देता है - पूरी तरह से समझ में आता है।
देव_विक्रम

11

सामान्य तौर continueपर finallyब्लॉक में इस्तेमाल होने पर इसका कोई मतलब नहीं है । इस पर एक नजर डालिए:

foreach (var item in list)
{
    try
    {
        throw new Exception();
    }
    finally{
        //doesn't make sense as we are after exception
        continue;
    }
}

"सामान्य तौर पर" बहुत सारी चीजें समझ में नहीं आती हैं। और इसका मतलब यह नहीं है कि यह "विशेष रूप से" काम नहीं करना चाहिए। IE: continueलूप स्टेटमेंट के बाहर कोई मतलब नहीं है, लेकिन इसका मतलब यह नहीं है कि यह समर्थित नहीं है।
zerkms

मुझे लगता है कि यह कुछ समझ में आता है। itemफ़ाइल हो सकती है, पढ़ने में विफल -> finallyफ़ाइल बंद कर देता है। continueबाकी प्रसंस्करण को रोकता है।
jnovacho

5

"यह संकलन नहीं होगा और मुझे लगता है कि यह पूरी तरह समझ में आता है"

खैर, मुझे लगता है कि यह नहीं है।

जब आपके पास शाब्दिक रूप से होता है catch(Exception)तो आपको अंत में (और शायद नहीं भी continue) की आवश्यकता नहीं होती है ।

जब आपके पास अधिक यथार्थवादी है catch(SomeException), तब क्या होना चाहिए जब कोई अपवाद नहीं पकड़ा जाता है? आपका continueएक रास्ता जाना चाहता है, अपवाद दूसरे को संभालना।


2
मुझे लगता है कि finallyआपके पास जब आप की जरूरत हो सकती है catch। यह आमतौर पर विश्वसनीय तरीके से संसाधनों को बंद करने के लिए उपयोग किया जाता है।
jnovacho

हालांकि यह अपवाद नहीं है। आप आसानी सेreturn अपने tryया catchब्लॉकों के भीतर एक बयान दे सकते हैं । अब हम क्या करें? लौटें या जारी रखें? (और अगर हम जारी रखते हैं, तो क्या होगा अगर यह अंतिम आइटम पुनरावृति करने के लिए है? तो हम सिर्फ बाहर जारी रखते हैं foreachऔर रिटर्न कभी नहीं होता है?) संपादित करें: या यहां तक gotoकि लूप के बाहर एक लेबल तक , बहुत अधिक कोई भी कार्रवाई जो foreachलूप के बाहर नियंत्रण स्थानांतरित करती है। ।
क्रिस सिनक्लेयर

2
मैं इससे सहमत नहीं हूं "जब आप सचमुच पकड़ लेते हैं (अपवाद) तो आपको अंत में (और शायद जारी भी नहीं है) की आवश्यकता नहीं है।" क्या होगा अगर मुझे एक ऑपरेशन करने की आवश्यकता है जो कुछ भी अपवाद ने उठाया है या नहीं?
lpaloub

ठीक है, अंत returnमें ब्लॉक के अंदर अतिरिक्त एस के लिए पूरा करता है । लेकिन आम तौर पर कैच-ऑल के बाद निष्पादन जारी रहता है।
हेनक होल्टरमैन

'आखिर ’' कैच’ नहीं है। इसका उपयोग सफाई कोड के लिए किया जाना चाहिए। आखिरकार यह परवाह किए बिना चलता है कि अपवाद फेंका गया है या नहीं । फाइलों को बंद करने जैसी स्टफ, या मेमोरी को खाली करना (यदि आप अनवांटेड कोड का उपयोग कर रहे हैं) आदि। ये वो चीजें हैं जिन्हें आप आखिरकार ब्लॉक में डालते हैं
रोबोटिक

3

आप अंत में ब्लॉक का शरीर नहीं छोड़ सकते। इसमें ब्रेक, रिटर्न और आपके मामले में कीवर्ड जारी रहना शामिल है।


3

finallyब्लॉक एक अपवाद rethrown होने के लिए इंतजार कर के साथ क्रियान्वित किया जा सकता। यह वास्तव continueमें अपवाद को फिर से डूबे बिना ब्लॉक ( या कुछ और) से बाहर निकलने में सक्षम नहीं होगा ।

यदि आप अपने लूप को जारी रखना चाहते हैं, तो जो भी हो, आपको अंतत: कथन की आवश्यकता नहीं है: बस अपवाद को पकड़ें और पुनर्विचार न करें।


1

finallyरन या नहीं एक अनकहा अपवाद फेंक दिया जाता है। दूसरों ने पहले ही समझाया है कि यह क्यों continueअतार्किक बनाता है , लेकिन यहां एक विकल्प है जो इस कोड की मांग करता प्रतीत होता है। मूल रूप से, finally { continue; }कह रहा है:

  1. जब अपवादों को पकड़ा जाता है, तो जारी रखें
  2. जब अपवाद नहीं होते हैं, तो उन्हें फेंकने की अनुमति दें, लेकिन फिर भी जारी रखें

(1) को continueप्रत्येक के अंत में रखकर संतुष्ट किया जा सकता है catch, और (2) बाद में फेंके जाने वाले अनछुए अपवादों को संग्रहीत करके संतुष्ट किया जा सकता है। आप इसे इस तरह लिख सकते हैं:

var exceptions = new List<Exception>();
foreach (var foo in list) {
    try {
        // some code
    } catch (InvalidOperationException ex) {
        // handle specific exception
        continue;
    } catch (Exception ex) {
        exceptions.Add(ex);
        continue;
    }
    // some more code
}
if (exceptions.Any()) {
    throw new AggregateException(exceptions);
}

वास्तव में, finallyतीसरे मामले में भी निष्पादित किया जाता था, जहां कोई अपवाद नहीं था, पकड़ा या अनकहा। यदि वह वांछित था, तो आप निश्चित रूप से continueप्रत्येक के अंदर की बजाय कोशिश-पकड़ने वाले ब्लॉक के बाद एक ही जगह कर सकते हैं catch


1

तकनीकी रूप से, यह अंतर्निहित सीआईएल की एक सीमा है। से भाषा कल्पना :

अपवाद हस्तांतरण तंत्र के अलावा नियंत्रण हस्तांतरण को पकड़ने वाले हैंडलर या अंत में क्लॉज में प्रवेश करने की अनुमति नहीं है।

तथा

(एक संरक्षित क्षेत्र से बाहर नियंत्रण हस्तांतरण केवल एक अपवाद अनुदेश के माध्यम से की अनुमति दी है leave, end.filter, end.catch, या end.finally)

brनिर्देश के लिए डॉक्टर पृष्ठ पर :

इस निर्देश द्वारा नियंत्रण, प्रयास, कैच, फिल्टर और अंत में ब्लॉक को स्थानांतरित किया जा सकता है।

यह पिछले के लिए सच है सभी शाखा निर्देश, सहित beq, brfalseआदि


-1

भाषा के डिजाइनर बस एक अंतरण खंड के शब्दार्थ के बारे में (या नहीं कर सकते) एक नियंत्रण हस्तांतरण द्वारा समाप्त किया जा रहा है।

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

यदि हमारे पास finallyसफाई ब्लॉक से बाहर नियंत्रण हस्तांतरण है , तो मूल नियंत्रण स्थानांतरण "अपहृत" किया जा रहा है। यह रद्द हो जाता है, और नियंत्रण कहीं और चला जाता है।

शब्दार्थों पर काम किया जा सकता है। अन्य भाषाओं में है।

C # के डिजाइनरों ने स्थिर, "गोटो-लाइक" नियंत्रण हस्तांतरण को अस्वीकार करने का फैसला किया, जिससे चीजें कुछ हद तक सरल हो गईं।

हालाँकि, यदि आप ऐसा करते हैं, तो भी यह इस सवाल का हल नहीं करता है कि क्या होता है यदि एक गतिशील स्थानांतरण एक से शुरू किया जाता है finally: क्या होगा यदि अंत में एक फ़ंक्शन कॉल करता है, और वह फ़ंक्शन फेंकता है? मूल अपवाद प्रसंस्करण तो "अपहृत" है।

यदि आप अपहरण के इस दूसरे रूप के शब्दार्थ पर काम करते हैं, तो पहले प्रकार को बंद करने का कोई कारण नहीं है। वे वास्तव में एक ही चीज हैं: एक नियंत्रण हस्तांतरण एक नियंत्रण हस्तांतरण है, चाहे वह एक ही शाब्दिक गुंजाइश हो या नहीं।


अंतर यह है कि finallyपरिभाषा को तुरंत उस स्थानांतरण को जारी रखने के बाद होना चाहिए जो इसे ट्रिगर करता है (एक अनकहा अपवाद return, आदि)। "गोटो-लाइक" को भीतर स्थानांतरित करना आसान होगा finally(कौन सी भाषाएं ऐसा करती हैं? वैसे), लेकिन ऐसा करने का मतलब होगा कि try { return } finally { ... } वापस नहीं आना , जो पूरी तरह से अप्रत्याशित है। यदि finallyकोई ऐसा फ़ंक्शन कहता है जो फेंकता है, तो यह वास्तव में एक ही बात नहीं है, क्योंकि हम पहले से ही उम्मीद करते हैं कि अपवाद किसी भी समय हो सकते हैं और सामान्य प्रवाह को बाधित कर सकते हैं।
nmclean

@nmclean: वास्तव में, एक अपवाद जो बच जाता है finallyवह है सॉर्टा एक ही चीज़, इसमें परिणाम अनपेक्षित और अतार्किक कार्यक्रम हो सकता है। अंतर केवल इतना है कि भाषा डिजाइनर, उन सभी कार्यक्रमों को अस्वीकार करने में असमर्थ हैं, जहां अंततः एक खंड खंडित अपवाद को फेंक सकता है, इसके बजाय ऐसे कार्यक्रमों को संकलित करने की अनुमति देता है और आशा करता है कि कार्यक्रम किसी भी परिणाम को स्वीकार कर सकता है जो पहले अपवाद-अपवाद को छोड़ सकता है। अनुक्रम।
सुपरकैट

@ सुपरकार मैं सहमत हूं कि यह अपेक्षित प्रवाह को तोड़ता है, लेकिन मेरा कहना यह है कि सदैव अनियंत्रित अपवादों की स्थिति है, चाहे वर्तमान प्रवाह एक हो finallyया न हो। काज़ के अंतिम पैराग्राफ के तर्क से, कार्यों को उनके कॉलर के दायरे में प्रवाह को प्रभावित करने के लिए स्वतंत्र होना चाहिए continueआदि, क्योंकि उन्हें अपवादों के माध्यम से ऐसा करने की अनुमति है। लेकिन इस पाठ्यक्रम की अनुमति नहीं है; अपवाद इस नियम का एकमात्र अपवाद हैं, इसलिए नाम "अपवाद" (या "व्यवधान")।
nmclean

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

@mmclean क्षमा करें, मैं इस बात से सहमत नहीं हूं कि "अपवाद" नाम कुछ "अपवाद नियम से" (नियंत्रण के संबंध में) C #, LOL के लिए विशिष्ट है। एक अपवाद का नियंत्रण प्रवाह बदल पहलू केवल एक गैर-स्थानीय गतिशील नियंत्रण हस्तांतरण है। उसी लेक्सिकल स्कोप के भीतर एक नियमित नियंत्रण स्थानांतरण (कोई अनइंडिंग नहीं हो रहा है) को उसी का एक विशेष मामला माना जा सकता है।
काज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.