अनुपलब्ध कोड, लेकिन एक अपवाद के साथ पहुंच योग्य


108

यह कोड एक एप्लिकेशन का हिस्सा है जो ODBC से जुड़े डेटाबेस से पढ़ता है और लिखता है। यह डेटाबेस में एक रिकॉर्ड बनाता है और फिर जांचता है कि क्या रिकॉर्ड सफलतापूर्वक बनाया गया है, तो वापस लौट रहा है true

नियंत्रण प्रवाह की मेरी समझ इस प्रकार है:

command.ExecuteNonQuery()Invalid​Operation​Exceptionजब "एक विधि कॉल वस्तु की वर्तमान स्थिति के लिए अमान्य है" फेंकने के लिए प्रलेखित है । इसलिए, यदि ऐसा होता है, तो tryब्लॉक का निष्पादन बंद हो जाएगा, finallyब्लॉक निष्पादित हो जाएगा, फिर return false;सबसे नीचे निष्पादित होगा ।

हालांकि, मेरी आईडीई का दावा है कि return false;अप्राप्य कोड है। और यह सच प्रतीत होता है, मैं इसे हटा सकता हूं और यह बिना किसी शिकायत के संकलित करता है। हालाँकि, मेरे लिए ऐसा लगता है जैसे कोड पथ के लिए कोई वापसी मान नहीं होगा जहाँ उल्लेखित अपवाद को फेंक दिया गया है।

private static bool createRecord(String table,
                                 IDictionary<String,String> data,
                                 System.Data.IDbConnection conn,
                                 OdbcTransaction trans) {

    [... some other code ...]

    int returnValue = 0;
    try {
        command.CommandText = sb.ToString();
        returnValue = command.ExecuteNonQuery();

        return returnValue == 1;
    } finally {
        command.Dispose();
    }

    return false;
}

यहाँ समझने में मेरी क्या त्रुटि है?



41
साइड नोट: Disposeस्पष्ट रूप से कॉल न करें , लेकिन डाल दें using:using (var command = ...) {command.CommandText = sb.ToString(); return command.ExecuteNonQuery(); }
दिमित्री बर्नचेन

7
एक finallyब्लॉक का मतलब आपके विचार से कुछ और है।
थोरबजोरन रेव एंडरसन

जवाबों:


149

संकलक चेतावनी (स्तर 2) CS0162

पता नहीं लगने वाला कोड

संकलक ने कोड का पता लगाया जो कभी भी निष्पादित नहीं किया जाएगा।

जो बस कह रहा है, कंपाइलर स्टैटिक एनालिसिस के माध्यम से पर्याप्त समझता है कि इसे कैंट तक नहीं पहुंचाया जा सकता है और इसे संकलित आईएल से पूरी तरह से हटा दिया जाता है (इसलिए आपकी चेतावनी)

नोट : आप डीबगर के साथ अनुपलब्ध कोड पर कदम रखने की कोशिश करके, या एक IL एक्सप्लोरर का उपयोग करके अपने स्वयं के लिए इस तथ्य को साबित कर सकते हैं

finallyएक पर चल सकते हैं अपवाद , (हालांकि कि एक तरफ) यह तथ्य (इस मामले में) नहीं बदलता है यह अभी भी एक हो जाएगा न आया हुआ अपवाद । एर्गो, आखिरी returnकी परवाह किए बिना कभी नहीं मारा जाएगा।

  • यदि आप कोड को अंतिम पर जारी रखना चाहते हैं return, तो आपका एकमात्र विकल्प कैच टू है अपवाद ;

  • यदि आप नहीं करते हैं, तो इसे छोड़ दें जिस तरह से यह है और इसे हटा दें return

उदाहरण

try 
{
    command.CommandText = sb.ToString();
    returnValue = command.ExecuteNonQuery();

    return returnValue == 1;
}
catch(<some exception>)
{
   // do something
}
finally 
{
    command.Dispose();
}

return false;

प्रलेखन उद्धृत करने के लिए

कोशिश अंत में (C # संदर्भ)

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

एक नियंत्रित अपवाद के भीतर, संबद्ध अंत में ब्लॉक को चलाने की गारंटी है। हालांकि, यदि अपवाद अखंडित है, तो अंत में ब्लॉक का निष्पादन इस बात पर निर्भर करता है कि अपवाद के संचालन को कैसे ट्रिगर किया जाता है। बदले में, यह निर्भर करता है कि आपका कंप्यूटर कैसे सेट किया गया है।

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

अंततः

IDisposableइंटरफ़ेस का समर्थन करने वाली किसी भी चीज़ का उपयोग करते समय (जो अप्रबंधित संसाधनों को जारी करने के लिए डिज़ाइन किया गया है), आप इसे एक usingबयान में लपेट सकते हैं । कंपाइलर ऑब्जेक्ट पर try {} finally {}आंतरिक और आंतरिक कॉल उत्पन्न करेगाDispose()


1
पहले वाक्यों में IL का क्या अर्थ है?
क्लॉकवर्क

2
@ क्लॉकवर्क IL उच्च-स्तरीय .NET भाषाओं में लिखे गए कोड के संकलन का एक उत्पाद है। एक बार जब आप इनमें से किसी एक भाषा में लिखे गए अपने कोड को संकलित करते हैं, तो आपको एक बाइनरी मिलेगी जो IL से बाहर की जाती है। ध्यान दें कि मध्यवर्ती भाषा को कभी-कभी सामान्य मध्यवर्ती भाषा (CIL) या Microsoft मध्यवर्ती भाषा (MSIL) भी कहा जाता है।
माइकल रान्डेल

1
कम शब्दों में, क्योंकि उन्होंने संभावनाएं नहीं पकड़ी हैं: या तो कोशिश तब तक चलती है जब तक कि यह रिटर्न हिट न हो जाए और इस तरह अंत में नीचे दिए गए रिटर्न को अनदेखा कर देता है या एक अपवाद फेंक दिया जाता है और यह कि वापसी कभी नहीं होती है क्योंकि फ़ंक्शन अपवाद होने के कारण बाहर निकल जाएगा फेंक दिया।
फ्लीपेप

86

अंत में ब्लॉक को निष्पादित किया जाएगा, फिर झूठे को निष्पादित करेगा; तल पर।

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

यदि आप अपवाद को निगलना चाहते हैं, तो आपको इसमें एक catchब्लॉक का उपयोग करना चाहिए throw


1
क्या उपरोक्त सिनपेट मामले के अपवाद में संकलित होगा, क्या लौटाया जाएगा?
एहसान सज्जाद

3
यह संकलन करता है, लेकिन यह कभी हिट नहीं होगा return falseक्योंकि यह @EhsanSajjad के बजाय एक अपवाद फेंक देगा
पैट्रिक

1
अजीब लगता है, संकलन करता है क्योंकि या तो यह बिना किसी अपवाद के मामले में बूल के लिए एक मूल्य लौटाएगा और अपवाद के मामले में कुछ भी नहीं होगा, इसलिए विधि के वापसी प्रकार को संतुष्ट करने के लिए कानूनी है?
एहसान सज्जाद

2
कंपाइलर सिर्फ लाइन को नजरअंदाज करेगा, यही चेतावनी है। तो वह अजीब क्यों है? @ ईशानसजद
पैट्रिक हॉफमैन

3
मजेदार तथ्य: यह वास्तव में गारंटी नहीं है कि कार्यक्रम में अपवाद नहीं पकड़ा गया है तो आखिरकार ब्लॉक चलेगा। युक्ति इसकी गारंटी नहीं देती है और शुरुआती CLRs ने अंततः ब्लॉक को निष्पादित नहीं किया है । मुझे लगता है कि 4.0 से शुरू (पहले हो सकता है) कि व्यवहार बदल गया, लेकिन अन्य रनटाइम्स अभी भी अलग तरह से व्यवहार कर सकते हैं। बल्कि आश्चर्यजनक व्यवहार के लिए बनाता है।
वू

27

चेतावनी इसलिए है क्योंकि आपने उपयोग नहीं किया catchऔर आपकी विधि मूल रूप से इस तरह लिखी गई है:

bool SomeMethod()
{
    return true;
    return false; // CS0162 Unreachable code detected
}

चूंकि आप finallyपूरी तरह से निपटान के लिए उपयोग करते हैं, इसलिए पसंदीदा समाधान usingपैटर्न का उपयोग करना है:

using(var command = new WhateverCommand())
{
     ...
}

यह पर्याप्त है, यह सुनिश्चित करने के लिए कि क्या Disposeकहा जाएगा। यह कोड ब्लॉक के सफल निष्पादन के बाद या (पहले) कॉल स्टैक में कुछ catch नीचे होने की गारंटी दी जाती है (माता-पिता कॉल डाउन, राइट?) हैं।

यदि यह निपटान के बारे में नहीं होगा, तो

try { ...; return true; } // only one return
finally { ... }

पर्याप्त है, क्योंकि आपको विधि के अंत में कभी नहीं लौटना falseहोगा (उस पंक्ति की कोई आवश्यकता नहीं है)। आपकी विधि या तो कमांड निष्पादन का परिणाम है ( trueया false) या अन्यथा एक अपवाद फेंक देगा ।


अपेक्षित अपवादों को लपेटकर स्वयं अपवादों को फेंकने पर विचार करें ( InvalidOperationException constructor देखें ):

try { ... }
catch(SomeExpectedException e)
{
    throw new SomeBetterExceptionWithExplanaition("...", e);
}

यह आमतौर पर नेस्टेड कॉल अपवाद की तुलना में कॉल करने वाले को कुछ अधिक सार्थक (उपयोगी) कहने के लिए उपयोग किया जाता है।


ज्यादातर बार आप वास्तव में बिना किसी अपवाद के परवाह नहीं करते हैं। कभी-कभी आपको यह सुनिश्चित करने की आवश्यकता होती है कि finallyअपवाद कहे जाने पर भी इसे कहा जाए। इस मामले में आप बस इसे स्वयं पकड़ लेते हैं और फिर से फेंक देते हैं ( इस उत्तर को देखें ):

try { ... }
catch { ...; throw; } // re-throw
finally { ... }

14

ऐसा लगता है, आप कुछ इस तरह की तलाश कर रहे हैं:

private static bool createRecord(string table,
                                 IDictionary<String,String> data,
                                 System.Data.IDbConnection conn,
                                 OdbcTransaction trans) {
  [... some other code ...]

  // Using: do not call Dispose() explicitly, but wrap IDisposable into using
  using (var command = ...) {
    try {
      // Normal flow:
      command.CommandText = sb.ToString();

      // True if and only if exactly one record affected
      return command.ExecuteNonQuery() == 1;
    }
    catch (DbException) {
      // Exceptional flow (all database exceptions)
      return false;
    }
  }
}

कृपया ध्यान दें, यह किसी भी अपवाद को finally निगल नहीं है

finally {
  // This code will be executed; the exception will be efficently re-thrown
}

// And this code will never be reached

8

आपके पास कोई catchब्लॉक नहीं है , इसलिए अपवाद अभी भी फेंक दिया गया है, जो रिटर्न को अवरुद्ध करता है।

अंत में ब्लॉक को निष्पादित किया जाएगा, फिर झूठे को निष्पादित करेगा; तल पर।

यह गलत है, क्योंकि अंत में ब्लॉक निष्पादित किया जाएगा, और फिर एक अनकहा अपवाद होगा।

finallyब्लॉक का उपयोग सफाई के लिए किया जाता है, और वे अपवाद को नहीं पकड़ते हैं। अपवाद को वापसी से पहले फेंक दिया जाता है, इसलिए, वापसी कभी नहीं होगी, क्योंकि अपवाद को पहले फेंक दिया गया है।

आपका आईडीई सही है कि यह कभी नहीं पहुंचेगा, क्योंकि अपवाद को फेंक दिया जाएगा। केवलcatch ब्लॉक अपवादों को पकड़ने में सक्षम हैं।

प्रलेखन से पढ़ना ,

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

यह स्पष्ट रूप से दिखाता है कि अंत में अपवाद को पकड़ने का इरादा नहीं है, और यदि आप catchबयान से पहले एक खाली बयान देते थे, तो आप सही होंगे finally


7

जब अपवाद को फेंक दिया जाता है, तो स्टैक खोलना होगा (निष्पादन फ़ंक्शन से बाहर निकल जाएगा) एक मान वापस किए बिना, और फ़ंक्शन के ऊपर स्टैक फ़्रेम में कोई भी पकड़ ब्लॉक इसके बजाय अपवाद को पकड़ लेगा।

अत, return false कभी निष्पादित नहीं होगा।

नियंत्रण प्रवाह को समझने के लिए अपवाद को मैन्युअल रूप से फेंकने का प्रयास करें:

try {
    command.CommandText = sb.ToString();
    returnValue = command.ExecuteNonQuery();

    // Try this.
    throw new Exception("See where this goes.");

    return returnValue == 1;
} finally {
    command.Dispose();
}

5

आपके कोड पर:

private static bool createRecord(String table, IDictionary<String,String> data, System.Data.IDbConnection conn, OdbcTransaction trans) {

    [... some other code ...]

    int returnValue = 0;
    try {
        command.CommandText = sb.ToString();
        returnValue = command.ExecuteNonQuery();

        return returnValue == 1; // You return here in case no exception is thrown
    } finally {
        command.Dispose(); //You don't have a catch so the exception is passed on if thrown
    }

    return false; // This is never executed because there was either one of the above two exit points of the method reached.
}

अंत में ब्लॉक को निष्पादित किया जाएगा, फिर झूठे को निष्पादित करेगा; तल पर

यह आपके तर्क का दोष है क्योंकि finallyब्लॉक अपवाद को नहीं पकड़ेगा और यह अंतिम रिटर्न स्टेटमेंट तक कभी नहीं पहुंचेगा।


4

अंतिम विवरण return falseअनुपलब्ध है, क्योंकि ट्राई ब्लॉक एक ऐसा catchभाग याद कर रहा है जो अपवाद को संभालता है, इसलिए finallyब्लॉक के बाद अपवाद को फिर से हटा दिया जाता है और निष्पादन अंतिम विवरण तक कभी नहीं पहुंचता है।


2

आपके पास अपने कोड में दो वापसी पथ हैं, जिनमें से दूसरा पहले की वजह से पहुंच से बाहर है। आपके tryब्लॉक में अंतिम विवरण return returnValue == 1;आपकी सामान्य वापसी प्रदान करता है, इसलिए आप कभी भी नहीं पहुंच सकतेreturn false; विधि ब्लॉक के अंत में ।

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

अपवाद पर प्रवाह के बारे में ... एक के बिना catch, finallyअपवाद पर पहले अपवाद को निष्पादित किया जाएगा फिर विधि से बाहर निकाल दिया जाएगा; कोई "वापसी" पथ नहीं है।

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