যদি একটি অবশেষে ব্লক একটি ব্যতিক্রম ছোঁড়ে তবে কী হবে?


266

যদি একটি অবশেষে ব্লক একটি ব্যতিক্রম ছুঁড়ে, ঠিক কি ঘটে?

বিশেষত, ব্যতিক্রমটি শেষ অবধি মাঝখানে ফেলে দেওয়া হলে কী হয়। এই ব্লকের বাকী বিবৃতিগুলি (পরে) প্রার্থিত হবে?

আমি সচেতন যে ব্যতিক্রমগুলি উপরের দিকে প্রচার করবে।


8
কেন শুধু চেষ্টা করবেন না? তবে এই ধরণের জিনিসগুলিতে, আমি সবচেয়ে বেশি পছন্দ করি তা হ'ল শেষ অবধি ফিরে আসার পরে অবশেষে ব্লক থেকে অন্য কোনও কিছু ফেরত। :)
ANeves

8
শেষ অবধি সমস্ত বিবৃতি কার্যকর করতে হবে। এটির কোনও ফিরতে পারে না। এমএসডিএন.মাইক্রোসফট.এইনস
টিম

উত্তর:


419

একটি পরিশেষে ব্লক একটি ব্যতিক্রম কি ছোঁড়ার তাহলে ঠিক হবে?

এই ব্যতিক্রমটি বাইরে থেকে উপরে প্রচার করে এবং উচ্চ স্তরে পরিচালনা করা যাবে (যা)।

আপনার অবশেষে ব্লকটি যেখানে ব্যতিক্রম ছুঁড়েছে তার বাইরে শেষ হবে না

যদি পূর্বের ব্যতিক্রমটি পরিচালনা করার সময় শেষ অবধি ব্লকটি কার্যকর করা হয় তবে সেই প্রথম ব্যতিক্রমটি নষ্ট হয়ে যায়।

সি # 4 ভাষার স্পেসিফিকেশন: 8.9.5: অবশেষে ব্লক যদি অন্য একটি ব্যতিক্রম ছুঁড়ে দেয় তবে বর্তমান ব্যতিক্রম প্রক্রিয়াটি বন্ধ করা হবে।


9
এটি একটি না ThreadAbortExceptionহলে পুরো অবশেষে ব্লকটি প্রথমে সমাপ্ত হবে, কারণ এটি একটি সমালোচনামূলক বিভাগ।
Dmytro শেভচেনকো

1
@ শেডাল - আপনি ঠিক বলেছেন তবে এটি কেবল "কিছু নির্দিষ্ট অ্যাসিনক্রোনাস ব্যতিক্রম", অর্থাৎ থ্রেডআবার্ট এক্সসেপশন এর ক্ষেত্রে প্রযোজ্য। সাধারণ 1-থ্রেড কোডের জন্য আমার উত্তর ধারণ করে।
হেন্ক হলটারম্যান

"প্রথম ব্যতিক্রম হারিয়ে গেছে" - এটি আসলে খুব অপ্রয়োজনীয়, ঘটনাক্রমে আমি আইডিজপোজযোগ্য অবজেক্টগুলি খুঁজে পাই যা ডিসপোজ () এ ব্যতিক্রম ছুঁড়ে ফেলে, যার ফলে ব্যতিক্রমটি "ব্যবহার" দফার ভিতরে হারিয়ে যায়।
অ্যালেক্স বার্টসেভ

"আমি আইডিস্পোজযোগ্য অবজেক্টসগুলি পাই যা ডিসপোজ () এ ব্যতিক্রম করে" - এটি অদ্ভুতভাবে বলা অদ্ভুত। এমএসডিএন-এ পড়ুন: এভিওআইডি ডিসপোজ (বুল) এর মধ্যে থেকে ব্যতীত বাদ দিয়ে একটি ব্যতিক্রম ছুঁড়ছে ...
হেন্ক হলটারম্যান

1
@ হেনকহোল্টারম্যান: সরাসরি সংযুক্ত প্রাথমিক হার্ড ডিস্কে ডিস্ক-পূর্ণ ত্রুটি খুব সাধারণ হয় না, তবে প্রোগ্রামগুলি কখনও কখনও অপসারণযোগ্য বা নেটওয়ার্কযুক্ত ডিস্কগুলিতে ফাইলগুলি লিখে থাকে; সমস্যাগুলির সাথে তাদের আরও অনেক বেশি সাধারণ হতে পারে। কোনও ফাইল পুরোপুরি লিখিত হওয়ার আগে যদি কেউ ইউএসবি স্টিকটি বের করে দেয় তবে তারা কোথায় চলেছে এবং ফাইলটি দুর্নীতিগ্রস্থ তা না পাওয়া পর্যন্ত অপেক্ষা করার চেয়ে তাত্ক্ষণিকভাবে তাদেরকে বলা ভাল be পূর্বের ত্রুটিটি প্রদানের সময় যখন বুদ্ধিমান আচরণ থাকে তখন তা হতে পারে, তবে যখন কোনও পূর্ববর্তী ত্রুটি না থাকে তখন সমস্যাটি অ-প্রতিবেদন না করিয়ে দেওয়া ভাল।
সুপারক্যাট

101

এই জাতীয় প্রশ্নের জন্য আমি ভিজ্যুয়াল স্টুডিওতে একটি খালি কনসোল অ্যাপ্লিকেশন প্রকল্পটি খোলার জন্য এবং একটি ছোট নমুনা প্রোগ্রাম লিখি:

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ব্লকগুলি কার্যকর করা হয়। দয়া করে নোট করুন যে ব্যতিক্রমটি ছুঁড়ে দেওয়ার পরে অবশেষে ব্লকের কোডটি কার্যকর করা হবে না (বাস্তবে, এই নমুনা প্রোগ্রামটিতে ভিজ্যুয়াল স্টুডিও আপনাকে সতর্কও করবে যে এটি অ্যাক্সেসযোগ্য কোড সনাক্ত করেছে):

অভ্যন্তরীণ ক্যাচ ব্লক হ্যান্ডলিং ব্যতিক্রম চেষ্টা ব্লক থেকে ছোঁড়া।
ইনার অবশেষে অবরুদ্ধ
শেষ অবধি ব্লক থেকে বহিরাগত ক্যাচ ব্লক হ্যান্ডলিং ব্যতিক্রম।
বাইরের অবশেষে অবরুদ্ধ

অতিরিক্ত মন্তব্য

মাইকেল দামাতভ যেমন উল্লেখ করেছেন, tryআপনি যদি কোনও (অভ্যন্তরীণ) catchব্লকে এটি পরিচালনা না করেন তবে ব্লকটি থেকে একটি ব্যতিক্রম "খাওয়া" হবে । আসলে, উপরের উদাহরণে পুনঃ নিক্ষেপ ব্যতিক্রম বাইরের ক্যাচ ব্লকে উপস্থিত হয় না does নীচে সামান্য পরিবর্তিত নমুনাটিকে আরও সুস্পষ্ট চেহারা হিসাবে দেখানোর জন্য:

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");
        }
    }
}

আউটপুট থেকে আপনি দেখতে পাচ্ছেন যে অভ্যন্তরীণ ব্যতিক্রমটি "হারানো" (অর্থাত্ উপেক্ষা করা):

ইনার অবশেষে অবরুদ্ধ
শেষ অবধি ব্লক থেকে বহিরাগত ক্যাচ ব্লক হ্যান্ডলিং ব্যতিক্রম।
বাইরের অবশেষে অবরুদ্ধ

2
আপনি আপনার অভ্যন্তরীণ ক্যাচে ব্যাতিক্রমটি ছুঁড়ে ফেলেছেন বলে 'ইনার অবশেষে ব্লক' এর উদাহরণটিতে কখনই পৌঁছানো যাবে না
থিওফানিস প্যান্টালাইডস

4
@ থোফানিস প্যান্টালাইডস: না, কোনও finallyব্লক (প্রায়শই) প্রায়শই কার্যকর করা হবে, এটি অভ্যন্তরীণ অবশেষে অবরুদ্ধ ব্লকের ক্ষেত্রেও রয়েছে (কেবল নমুনা প্রোগ্রামটি নিজে চেষ্টা করে দেখুন (একটি অবশেষে ব্লকটি পুনরুদ্ধারযোগ্য না হওয়ার ক্ষেত্রে কার্যকর করা হবে না) ব্যতিক্রম, যেমন একটি EngineExecutionException, কিন্তু এই ধরনের একটি ক্ষেত্রে আপনার প্রোগ্রাম অবিলম্বে যাহাই হউক না কেন বন্ধ করে দেব)।
ডির্ক Vollmar

1
আপনার কোডের প্রথম টুকরোটির প্রথম ধরাতে নিক্ষেপের ভূমিকা কী তা আমি দেখতে পাচ্ছি না। আমি একটি কনসোল অ্যাপ্লিকেশন দিয়ে এবং এটি ছাড়া চেষ্টা করেছি, কোনও ভিন্নতা পাওয়া যায় নি।
জনপান

@ জোহনপান: বক্তব্যটি দেখানো ছিল যে শেষ অবধি সর্বদা কার্যকর হয়, এমনকি চেষ্টা এবং ধরা ব্লক উভয়ই ব্যতিক্রম ছুঁড়ে মারে। কনসোল আউটপুটটিতে আসলেই কোনও পার্থক্য নেই।
ডার্ক ভোলমার 12

10

যদি কোনও ব্যতিক্রম মুলতুবি থাকে (যখন tryব্লকের একটি finallyকিন্তু না থাকে catch), নতুন ব্যতিক্রমটি এটিকে প্রতিস্থাপন করে।

যদি কোনও ব্যতিক্রম মুলতুবি না থাকে, তবে এটি finallyব্লকের বাইরে কেবল একটি ব্যতিক্রম ছুঁড়ে মারার মতো কাজ করে ।


যদি সেখানে ব্যতিক্রম এছাড়াও মুলতুবী করা যেতে পারে হয় একটি মানানসই catchব্লক যে (পুনরায়) একটি ব্যতিক্রম ছোঁড়ার।
স্টাকেক্স


3

"আসল ব্যতিক্রম" ( tryঅবরুদ্ধ নিক্ষেপ ) সংরক্ষণ এবং "শেষ অবধি" ত্যাগ করার জন্য দ্রুত (এবং বরং স্পষ্ট) স্নিপেট (এতে ছুঁড়েfinally ব্লকের ), যদি মূলটি আপনার জন্য আরও গুরুত্বপূর্ণ হয়:

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

উপরের কোডটি কার্যকর করা হলে, "আসল ব্যতিক্রম" কল স্ট্যাক প্রচার করে এবং "শেষ পর্যন্ত ব্যতিক্রম" হারিয়ে যায় "


2

একটি ব্যতিক্রমের কারণে কখনও খোলা হয়নি এমন স্ট্রিমটি বন্ধ করার চেষ্টা করার সময় ত্রুটি ধরার জন্য আমাকে এই কাজটি করতে হয়েছিল।

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();
    }
}

যদি ওয়েব রিকুয়েস্ট তৈরি করা হয়েছিল তবে সেই সময়ে সংযোগ ত্রুটি ঘটেছে

using (var sw = webRequest.GetRequestStream())

এরপরে অবশেষে এমন একটি ব্যতিক্রম ধরা পড়বে যেগুলি মনে করে যে সংযোগগুলি উন্মুক্ত ছিল তা বন্ধ করে দেওয়ার চেষ্টা করেছিল কারণ ওয়েব রিকুইস্ট তৈরি হয়েছিল।

যদি শেষ অবধি ভিতরে চেষ্টা করে না থাকে তবে ওয়েব রিকোয়েস্ট সাফ করার সময় এই কোডটি অবিচ্ছিন্ন ব্যতিক্রম ঘটায়

if (webRequest.GetRequestStream() != null) 

সেখান থেকে কোডটি ত্রুটিটি যথাযথভাবে পরিচালনা না করেই প্রস্থান করবে এবং সুতরাং কলিং পদ্ধতির জন্য সমস্যা তৈরি করে।

আশা করি এটি উদাহরণ হিসাবে সাহায্য করবে


1

অন্য ব্যতিক্রম সক্রিয় থাকাকালীন একটি ব্যতিক্রম ছোঁড়ার ফলে প্রথম ব্যতিক্রম দ্বিতীয় (পরে) ব্যতিক্রম দ্বারা প্রতিস্থাপিত হবে।

এখানে কিছু কোড রয়েছে যা চিত্রিত করে যা ঘটেছিল:

    public static void Main(string[] args)
    {
        try
        {
            try
            {
                throw new Exception("first exception");
            }
            finally
            {
                //try
                {
                    throw new Exception("second exception");
                }
                //catch (Exception)
                {
                    //throw;
                }
            }
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
        }
    }
  • কোডটি চালান এবং আপনি "দ্বিতীয় ব্যতিক্রম" দেখতে পাবেন
  • চেষ্টা করুন এবং বিবৃতি ধরুন মন্তব্য করুন এবং আপনি "প্রথম ব্যতিক্রম" দেখতে পাবেন
  • এছাড়াও নিক্ষেপ বিরক্তিহীন; বিবৃতি এবং আপনি আবার "দ্বিতীয় ব্যতিক্রম" দেখতে পাবেন।

এটি লক্ষণীয় যে "" গুরুতর "ব্যতিক্রম পরিষ্কার করার পক্ষে এটি কেবল একটি নির্দিষ্ট কোড ব্লকের বাইরে ধরা পড়বে যার মধ্যে এটি ধরা পড়ে এবং পরিচালনা করা হয় exception ব্যতিক্রম ফিল্টার ব্যবহার করে (vb.net এ উপলব্ধ, যদিও সি # নয়) এই শর্তটি সনাক্ত করা সম্ভব। কোডটি "হ্যান্ডেল" করতে পারে এমন পুরো কিছু নেই, যদিও কেউ যদি কোনও ধরণের লগিং ফ্রেমওয়ার্ক ব্যবহার করে থাকে তবে এটি অবশ্যই লগিংয়ের পক্ষে মূল্যবান। সিস্টেম মল্টটাউন ক্লিনআপ ট্রিগার এর মধ্যে ঘটে যাওয়া ব্যতিক্রমগুলির সি ++ পন্থাটি কুৎসিত, তবে ব্যতিক্রমগুলি অদৃশ্য হওয়া আইএমএইচও জঘন্য।
সুপারক্যাট

1

কয়েক মাস আগেও আমি এরকম কিছু মুখোমুখি হয়েছি,

    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);
}

তবে আপনি যদি প্যারামিটারগুলি ব্যবহার করতে চান এবং প্রকারগুলি ফিরে যান তবে এটি অন্য গল্প


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

কোডএ এবং কোডবি যেভাবে ব্যতিক্রম হয়েছে তা হ্যান্ডেল করা একই।

একটি finallyব্লকে ফেলে দেওয়া ব্যতিক্রমের বিশেষ কিছু নেই, এটিকে কোড বি দ্বারা ব্যতিক্রম হিসাবে গণ্য করুন treat


আপনি বিস্তারিত বলতে পারেন? আপনার ব্যতিক্রমগুলি কী একই রকম?
ডার্ক ভোলমার

1

ব্যতিক্রমটি প্রচার করে এবং একটি উচ্চ স্তরে পরিচালনা করা উচিত। যদি ব্যতিক্রমটি উচ্চ স্তরে পরিচালনা না করা হয় তবে অ্যাপ্লিকেশন ক্রাশ হয়ে যায়। "অবশেষে" ব্লক এক্সিকিউশনটি সেই স্থানে থামে যেখানে ব্যতিক্রম ছুঁড়ে দেওয়া হয়।

ব্যতিক্রম আছে কিনা তা নির্বিশেষে "অবশেষে" ব্লকটি কার্যকর করার গ্যারান্টিযুক্ত।

  1. ট্রাই ব্লকে কোনও ব্যতিক্রম ঘটে যাওয়ার পরে যদি "অবশেষে" ব্লকটি কার্যকর করা হয়,

  2. এবং যদি সেই ব্যতিক্রমটি পরিচালনা না করা হয়

  3. এবং যদি শেষ অবধি ব্লকটি ব্যতিক্রম ছুঁড়ে

তারপরে ট্রাই ব্লকে যে ব্যতিক্রম ঘটেছিল তা হারিয়ে গেছে is

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");
        }
    }
} 

বিশদ জন্য দুর্দান্ত নিবন্ধ


-1

এটি একটি ব্যতিক্রম ছুঁড়ে;) আপনি এই ব্যতিক্রমটি অন্য কোনও ক্যাচ ক্লজেও ধরতে পারেন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.