c# क्या होता है यदि आखिरकार ब्लॉक अपवाद फेंकता है?




exception exception-handling (9)

यदि आखिरकार ब्लॉक एक अपवाद फेंकता है, तो वास्तव में क्या होता है?

विशेष रूप से, क्या होता है यदि अपवाद को आखिरकार ब्लॉक के माध्यम से मिडवे फेंक दिया जाता है। क्या इस ब्लॉक में शेष बयान (बाद में) आते हैं?

मुझे पता है कि अपवाद ऊपर फैल जाएगा।


मुझे ऐसा स्ट्रीम बंद करने की कोशिश में त्रुटि को पकड़ने के लिए ऐसा करना पड़ा जो अपवाद के कारण कभी नहीं खोला गया था।

errorMessage = string.Empty;

try
{
    byte[] requestBytes = System.Text.Encoding.ASCII.GetBytes(xmlFileContent);

    webRequest = WebRequest.Create(url);
    webRequest.Method = "POST";
    webRequest.ContentType = "text/xml;charset=utf-8";
    webRequest.ContentLength = requestBytes.Length;

    //send the request
    using (var sw = webRequest.GetRequestStream()) 
    {
        sw.Write(requestBytes, 0, requestBytes.Length);
    }

    //get the response
    webResponse = webRequest.GetResponse();
    using (var sr = new StreamReader(webResponse.GetResponseStream()))
    {
        returnVal = sr.ReadToEnd();
        sr.Close();
    }
}
catch (Exception ex)
{
    errorMessage = ex.ToString();
}
finally
{
    try
    {
        if (webRequest.GetRequestStream() != null)
            webRequest.GetRequestStream().Close();
        if (webResponse.GetResponseStream() != null)
            webResponse.GetResponseStream().Close();
    }
    catch (Exception exw)
    {
        errorMessage = exw.ToString();
    }
}

यदि webRequest बनाया गया था लेकिन कनेक्शन के दौरान एक कनेक्शन त्रुटि हुई

using (var sw = webRequest.GetRequestStream())

तो आखिरकार कनेक्शन को बंद करने की कोशिश कर रहे अपवाद को पकड़ लिया जाएगा, जिसे सोचा गया था क्योंकि वेबरक्वेट बनाया गया था।

अगर आखिर में अंदरूनी कोशिश नहीं की गई, तो वेब कोड की सफाई करते समय यह कोड एक अनचाहे अपवाद का कारण बन जाएगा

if (webRequest.GetRequestStream() != null) 

वहां से कोड उत्पन्न होने वाली त्रुटि को सही ढंग से संभालने के बिना बाहर निकल जाएगा और इसलिए कॉलिंग विधि के लिए समस्याएं उत्पन्न हो रही हैं।

उम्मीद है कि यह एक उदाहरण के रूप में मदद करता है


यदि आखिरकार ब्लॉक एक अपवाद फेंकता है तो वास्तव में क्या होता है?

वह अपवाद ऊपर और ऊपर फैलता है, और उच्च स्तर पर (कर सकते हैं) संभाला जाएगा।

आपका आखिरी ब्लॉक उस बिंदु से परे पूरा नहीं होगा जहां अपवाद फेंक दिया गया है।

यदि अंत में ब्लॉक पहले के अपवाद के संचालन के दौरान निष्पादित कर रहा था तो पहला अपवाद खो गया है।

सी # 4 भाषा विशिष्टता § 8.9.5: यदि अंत में ब्लॉक एक और अपवाद फेंकता है, तो मौजूदा अपवाद की प्रक्रिया समाप्त हो जाती है।


इन सवालों के लिए मैं आमतौर पर विजुअल स्टूडियो में एक खाली कंसोल एप्लिकेशन प्रोजेक्ट खोलता हूं और एक छोटा सा नमूना प्रोग्राम लिखता हूं:

using System;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            try
            {
                throw new Exception("exception thrown from try block");
            }
            catch (Exception ex)
            {
                Console.WriteLine("Inner catch block handling {0}.", ex.Message);
                throw;
            }
            finally
            {
                Console.WriteLine("Inner finally block");
                throw new Exception("exception thrown from finally block");
                Console.WriteLine("This line is never reached");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Outer catch block handling {0}.", ex.Message);
        }
        finally
        {
            Console.WriteLine("Outer finally block");
        }
    }
}

जब आप प्रोग्राम चलाते हैं तो आपको सटीक ऑर्डर दिखाई देगा जिसमें catch और finally ब्लॉक निष्पादित किए जाते हैं। कृपया ध्यान दें कि अपवाद के बाद आखिरकार ब्लॉक में कोड निष्पादित नहीं किया जाएगा (वास्तव में, इस नमूना कार्यक्रम में विजुअल स्टूडियो आपको चेतावनी भी देगा कि उसे पहुंचने योग्य कोड नहीं मिला है):

Inner catch block handling exception thrown from try block.
Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block

अतिरिक्त टिप्पणी

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

using System;

class Program
{
    static void Main(string[] args)
    {
        try
        {
            try
            {
                throw new Exception("exception thrown from try block");
            }
            finally
            {
                Console.WriteLine("Inner finally block");
                throw new Exception("exception thrown from finally block");
                Console.WriteLine("This line is never reached");
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("Outer catch block handling {0}.", ex.Message);
        }
        finally
        {
            Console.WriteLine("Outer finally block");
        }
    }
}

जैसा कि आप आउटपुट से देख सकते हैं आंतरिक अपवाद "खो गया" है (यानी अनदेखा):

Inner finally block
Outer catch block handling exception thrown from finally block.
Outer finally block

यह एक अपवाद फेंकता है;) आप किसी अन्य पकड़ खंड में उस अपवाद को पकड़ सकते हैं।


अपवाद फैलता है, और उच्च स्तर पर संभाला जाना चाहिए। यदि अपवाद उच्च स्तर पर संभाला नहीं जाता है, तो एप्लिकेशन क्रैश हो जाता है। "आखिरकार" ब्लॉक निष्पादन उस बिंदु पर बंद हो जाता है जहां अपवाद फेंक दिया जाता है।

चाहे कोई अपवाद है या नहीं, "आखिरकार" ब्लॉक निष्पादित करने की गारंटी है या नहीं।

  1. यदि कोशिश ब्लॉक में अपवाद होने के बाद "आखिरकार" ब्लॉक निष्पादित किया जा रहा है,

  2. और अगर वह अपवाद संभाला नहीं जाता है

  3. और यदि अंत में ब्लॉक एक अपवाद फेंकता है

फिर कोशिश ब्लॉक में हुआ मूल अपवाद खो गया है।

public class Exception
{
    public static void Main()
    {
        try
        {
            SomeMethod();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }

    public static void SomeMethod()
    {
        try
        {
            // This exception will be lost
            throw new Exception("Exception in try block");
        }
        finally
        {
            throw new Exception("Exception in finally block");
        }
    }
} 

विवरण के लिए महान लेख


public void MyMethod()
{
   try
   {
   }
   catch{}
   finally
   {
      CodeA
   }
   CodeB
}

जिस तरह से कोडेए और कोडेबी द्वारा दिए गए अपवादों को संभाला जाता है वही है।

finally ब्लॉक में फेंक दिया गया अपवाद कुछ खास नहीं है, इसे कोड बी द्वारा अपवाद फेंकने के रूप में माना जाता है।


यदि कोई अपवाद लंबित है (जब try ब्लॉक finally लेकिन कोई catch नहीं है), तो नया अपवाद उस स्थान को बदल देता है।

यदि कोई अपवाद लंबित नहीं है, तो यह finally ब्लॉक के बाहर एक अपवाद फेंकने के रूप में काम करता है।


मूल (एक और स्पष्ट) स्निपेट को "मूल अपवाद" ( try ब्लॉक में फेंक दिया गया) और "अंततः अपवाद" ( finally ब्लॉक में फेंक दिया गया) को बचाने के लिए स्निपेट, यदि मूल आपके लिए अधिक महत्वपूर्ण है:

try
{
    throw new Exception("Original Exception");
}
finally
{
    try
    {
        throw new Exception("Finally Exception");
    }
    catch
    { }
}

जब उपरोक्त कोड निष्पादित किया जाता है, तो "मूल अपवाद" कॉल स्टैक को प्रसारित करता है, और "अंत में अपवाद" खो जाता है।


कुछ महीने पहले मुझे इस तरह कुछ सामना करना पड़ा,

    private  void RaiseException(String errorMessage)
    {
        throw new Exception(errorMessage);
    }

    private  void DoTaskForFinally()
    {
        RaiseException("Error for finally");
    }

    private  void DoTaskForCatch()
    {
        RaiseException("Error for catch");
    }

    private  void DoTaskForTry()
    {
        RaiseException("Error for try");
    }


        try
        {
            /*lacks the exception*/
            DoTaskForTry();
        }
        catch (Exception exception)
        {
            /*lacks the exception*/
            DoTaskForCatch();
        }
        finally
        {
            /*the result exception*/
            DoTaskForFinally();
        }

ऐसी समस्या को हल करने के लिए मैंने एक उपयोगिता वर्ग बनाया है

class ProcessHandler : Exception
{
    private enum ProcessType
    {
        Try,
        Catch,
        Finally,
    }

    private Boolean _hasException;
    private Boolean _hasTryException;
    private Boolean _hasCatchException;
    private Boolean _hasFinnallyException;

    public Boolean HasException { get { return _hasException; } }
    public Boolean HasTryException { get { return _hasTryException; } }
    public Boolean HasCatchException { get { return _hasCatchException; } }
    public Boolean HasFinnallyException { get { return _hasFinnallyException; } }
    public Dictionary<String, Exception> Exceptions { get; private set; } 

    public readonly Action TryAction;
    public readonly Action CatchAction;
    public readonly Action FinallyAction;

    public ProcessHandler(Action tryAction = null, Action catchAction = null, Action finallyAction = null)
    {

        TryAction = tryAction;
        CatchAction = catchAction;
        FinallyAction = finallyAction;

        _hasException = false;
        _hasTryException = false;
        _hasCatchException = false;
        _hasFinnallyException = false;
        Exceptions = new Dictionary<string, Exception>();
    }


    private void Invoke(Action action, ref Boolean isError, ProcessType processType)
    {
        try
        {
            action.Invoke();
        }
        catch (Exception exception)
        {
            _hasException = true;
            isError = true;
            Exceptions.Add(processType.ToString(), exception);
        }
    }

    private void InvokeTryAction()
    {
        if (TryAction == null)
        {
            return;
        }
        Invoke(TryAction, ref _hasTryException, ProcessType.Try);
    }

    private void InvokeCatchAction()
    {
        if (CatchAction == null)
        {
            return;
        }
        Invoke(TryAction, ref _hasCatchException, ProcessType.Catch);
    }

    private void InvokeFinallyAction()
    {
        if (FinallyAction == null)
        {
            return;
        }
        Invoke(TryAction, ref _hasFinnallyException, ProcessType.Finally);
    }

    public void InvokeActions()
    {
        InvokeTryAction();
        if (HasTryException)
        {
            InvokeCatchAction();
        }
        InvokeFinallyAction();

        if (HasException)
        {
            throw this;
        }
    }
}

और इस तरह इस्तेमाल किया

try
{
    ProcessHandler handler = new ProcessHandler(DoTaskForTry, DoTaskForCatch, DoTaskForFinally);
    handler.InvokeActions();
}
catch (Exception exception)
{
    var processError = exception as ProcessHandler;
    /*this exception contains all exceptions*/
    throw new Exception("Error to Process Actions", exception);
}

लेकिन अगर आप paramaters का उपयोग करना चाहते हैं और एक अन्य कहानी है कि वापसी प्रकार





try-catch-finally