"নিক্ষেপ" এবং "নিক্ষেপ প্রাক্তন" মধ্যে পার্থক্য আছে?


437

কিছু পোস্ট রয়েছে যা জিজ্ঞাসা করেছে যে ইতিমধ্যে দুজনের মধ্যে পার্থক্য কী।
(কেন আমি এমনকি এটি উল্লেখ করতে হবে ...)

তবে আমার প্রশ্নটি এমনভাবে আলাদা যে আমি handশ্বরের মতো পরিচালনার পদ্ধতিতে অন্য একটি ত্রুটিটিকে "থ্রো প্রাক্তন" বলছি ।

public class Program {
    public static void Main(string[] args) {
        try {
            // something
        } catch (Exception ex) {
            HandleException(ex);
        }
    }

    private static void HandleException(Exception ex) {
        if (ex is ThreadAbortException) {
            // ignore then,
            return;
        }
        if (ex is ArgumentOutOfRangeException) { 
            // Log then,
            throw ex;
        }
        if (ex is InvalidOperationException) {
            // Show message then,
            throw ex;
        }
        // and so on.
    }
}

যদি try & catchব্যবহার করা হয় Main, তবে আমি throw;ত্রুটিটি পুনর্বিবেচনা করতে ব্যবহার করব । তবে উপরের সরল কোডে, সমস্ত ব্যতিক্রম এর মধ্য দিয়ে যায়HandleException

নেই throw ex;কলিং হিসাবে একই প্রভাব রয়েছে throwযখন ভিতরে নামক HandleException?


3
একটি পার্থক্য রয়েছে, স্ট্যাকের ট্রেসটি কীভাবে ব্যতিক্রম হিসাবে প্রদর্শিত হবে বা কীভাবে তা করতে হবে, তবে এখনই কোনটি ঠিক তা কোনটিই আমি মনে করি না তাই আমি এই উত্তরটির তালিকা করবো না।
জোয়েল কোহোর্ন 14

@ জোয়েল: ধন্যবাদ আমার ধারণা হ্যান্ডলিরর ব্যতিক্রমটি খারাপ ধারণা। আমি কেবল কিছু ত্রুটি পরিচালনা করার কোডটি রিফ্যাক্টর করতে চেয়েছিলাম।
নাচ

1
তৃতীয় উপায়টি হ'ল
টিম আবেল

উত্তর:


679

হ্যাঁ, একটি পার্থক্য আছে;

  • throw exস্ট্যাক ট্রেস পুনরায় সেট করুন (যাতে আপনার ত্রুটিগুলি থেকে উদ্ভূত হবে HandleException)
  • throw না - আসল অপরাধী সংরক্ষণ করা হবে।

    static void Main(string[] args)
    {
        try
        {
            Method2();
        }
        catch (Exception ex)
        {
            Console.Write(ex.StackTrace.ToString());
            Console.ReadKey();
        }
    }
    
    private static void Method2()
    {
        try
        {
            Method1();
        }
        catch (Exception ex)
        {
            //throw ex resets the stack trace Coming from Method 1 and propogates it to the caller(Main)
            throw ex;
        }
    }
    
    private static void Method1()
    {
        try
        {
            throw new Exception("Inside Method1");
        }
        catch (Exception)
        {
            throw;
        }
    }

28
মার্কের উত্তরটি কিছুটা প্রসারিত করতে, আপনি এখানে আরও বিশদ জানতে পারেন: geekswithblogs.net/sdorman/archive/2007/08/20/…
স্কট ডরম্যান

3
@Shaul; না, এটা না। আমি আপনার পোস্টে একটি মন্তব্যে বিশদ দিয়েছি।
মার্ক Gravell

1
@ মার্ক গ্র্যাভেল - আমার দুঃখিত, আপনি ঠিক বলেছেন you ডাউনভোট সম্পর্কে দুঃখিত; আমার পূর্বাবস্থায় ফিরে আসতে দেরি হয়ে গেছে ... :(
শৈল বেহর

3
@Marc: মনে হচ্ছে যে থ্রো মূল অপরাধী শুধুমাত্র যদি থ্রো পদ্ধতি যা প্রাথমিক ব্যতিক্রম নিহিত ছিল নয় অপরিবর্তিত (এই প্রশ্ন দেখুন: stackoverflow.com/questions/5152265/... )
Brann

3
@ স্কটডোরম্যান দেখে মনে হচ্ছে কোনও ব্লগ স্থানান্তরের পরে আপনার লিঙ্কটি সঠিকভাবে ফরোয়ার্ড করা হচ্ছে না। দেখে মনে হচ্ছে এটি এখন এখানে বাস করেসম্পাদনা: আরে, অপেক্ষা করুন, এটি আপনার ব্লগ! আপনার নিজস্ব লিঙ্কগুলি ঠিক করুন! ;
রাফিন

96

(আমি আগে পোস্ট করেছি, এবং @ মার্ক গ্র্যাভেল আমাকে সংশোধন করেছে)

পার্থক্যটির একটি প্রদর্শন এখানে দেওয়া হয়েছে:

static void Main(string[] args) {
    try {
        ThrowException1(); // line 19
    } catch (Exception x) {
        Console.WriteLine("Exception 1:");
        Console.WriteLine(x.StackTrace);
    }
    try {
        ThrowException2(); // line 25
    } catch (Exception x) {
        Console.WriteLine("Exception 2:");
        Console.WriteLine(x.StackTrace);
    }
}

private static void ThrowException1() {
    try {
        DivByZero(); // line 34
    } catch {
        throw; // line 36
    }
}
private static void ThrowException2() {
    try {
        DivByZero(); // line 41
    } catch (Exception ex) {
        throw ex; // line 43
    }
}

private static void DivByZero() {
    int x = 0;
    int y = 1 / x; // line 49
}

এবং এখানে ফলাফল:

Exception 1:
   at UnitTester.Program.DivByZero() in <snip>\Dev\UnitTester\Program.cs:line 49
   at UnitTester.Program.ThrowException1() in <snip>\Dev\UnitTester\Program.cs:line 36
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 19

Exception 2:
   at UnitTester.Program.ThrowException2() in <snip>\Dev\UnitTester\Program.cs:line 43
   at UnitTester.Program.TestExceptions() in <snip>\Dev\UnitTester\Program.cs:line 25

আপনি দেখতে পাচ্ছেন যে ব্যতিক্রম 1 এ, স্ট্যাক ট্রেসটি DivByZero()পদ্ধতিতে ফিরে যায় , তবে ব্যতিক্রম 2 এ এটি হয় না।

তবে খেয়াল করুন, যে লাইন নম্বরটি দেখানো হয়েছে ThrowException1()এবং ThrowException2()এটি throwবিবৃতিটির লাইন নম্বর, কল করার লাইন নম্বর নয়DivByZero() , যা সম্ভবত এখন বোধগম্য হয় যে আমি এটি সম্পর্কে কিছুটা চিন্তা করি ...

রিলিজ মোডে আউটপুট

ব্যতিক্রম 1:

at ConsoleAppBasics.Program.ThrowException1()
at ConsoleAppBasics.Program.Main(String[] args)

ব্যতিক্রম 2:

at ConsoleAppBasics.Program.ThrowException2()
at ConsoleAppBasics.Program.Main(String[] args)

এটি কি কেবল ডিবাগ মোডে মূল স্ট্যাকট্রেস বজায় রাখে?


1
এটি কারণ কারণ সংকলকটির অপ্টিমাইজেশন প্রক্রিয়া সংক্ষিপ্ত পদ্ধতিগুলির যেমন ইনলাইন করে DevideByZero, তাই স্ট্যাক ট্রেসটি একই। হতে পারে আপনার নিজের একটি প্রশ্ন হিসাবে এটি পোস্ট করা উচিত
মেনাহেম

42

অন্যান্য উত্তরগুলি সম্পূর্ণ সঠিক, তবে এই উত্তরটি কিছু অতিরিক্ত ডেটালিস সরবরাহ করে, আমার ধারণা।

এই উদাহরণ বিবেচনা করুন:

using System;

static class Program {
  static void Main() {
    try {
      ThrowTest();
    } catch (Exception e) {
      Console.WriteLine("Your stack trace:");
      Console.WriteLine(e.StackTrace);
      Console.WriteLine();
      if (e.InnerException == null) {
        Console.WriteLine("No inner exception.");
      } else {
        Console.WriteLine("Stack trace of your inner exception:");
        Console.WriteLine(e.InnerException.StackTrace);
      }
    }
  }

  static void ThrowTest() {
    decimal a = 1m;
    decimal b = 0m;
    try {
      Mult(a, b);  // line 34
      Div(a, b);   // line 35
      Mult(b, a);  // line 36
      Div(b, a);   // line 37
    } catch (ArithmeticException arithExc) {
      Console.WriteLine("Handling a {0}.", arithExc.GetType().Name);

      //   uncomment EITHER
      //throw arithExc;
      //   OR
      //throw;
      //   OR
      //throw new Exception("We handled and wrapped your exception", arithExc);
    }
  }

  static void Mult(decimal x, decimal y) {
    decimal.Multiply(x, y);
  }
  static void Div(decimal x, decimal y) {
    decimal.Divide(x, y);
  }
}

আপনি যদি throw arithExc;লাইনটি আপত্তিহীন করেন তবে আপনার আউটপুটটি হ'ল:

Handling a DivideByZeroException.
Your stack trace:
   at Program.ThrowTest() in c:\somepath\Program.cs:line 44
   at Program.Main() in c:\somepath\Program.cs:line 9

No inner exception.

অবশ্যই, যেখানে ব্যতিক্রম ঘটেছিল সে সম্পর্কে আপনি তথ্য হারিয়েছেন। পরিবর্তে আপনি যদি throw;লাইনটি ব্যবহার করেন তবে এটি যা পাবেন:

Handling a DivideByZeroException.
Your stack trace:
   at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
   at System.Decimal.Divide(Decimal d1, Decimal d2)
   at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
   at Program.ThrowTest() in c:\somepath\Program.cs:line 46
   at Program.Main() in c:\somepath\Program.cs:line 9

No inner exception.

এটি অনেক ভাল, কারণ এখন আপনি দেখতে পাচ্ছেন যে এটি সেই Program.Divপদ্ধতি যা আপনাকে সমস্যার কারণ করেছিল। তবে সমস্যাটি tryব্লকের 35 লাইন বা লাইন 37 থেকে আসে কিনা তা দেখতে এখনও শক্ত ।

যদি আপনি তৃতীয় বিকল্প ব্যবহার করেন তবে বাহ্যিক ব্যতিক্রম মোড়ানো, আপনি কোনও তথ্য হারাবেন না:

Handling a DivideByZeroException.
Your stack trace:
   at Program.ThrowTest() in c:\somepath\Program.cs:line 48
   at Program.Main() in c:\somepath\Program.cs:line 9

Stack trace of your inner exception:
   at System.Decimal.FCallDivide(Decimal& d1, Decimal& d2)
   at System.Decimal.Divide(Decimal d1, Decimal d2)
   at Program.Div(Decimal x, Decimal y) in c:\somepath\Program.cs:line 58
   at Program.ThrowTest() in c:\somepath\Program.cs:line 35

বিশেষত আপনি দেখতে পারেন যে এটি 35 লাইন যা সমস্যার দিকে পরিচালিত করে। তবে এর জন্য লোকেরা অনুসন্ধান করতে InnerExceptionহবে এবং সাধারণ ক্ষেত্রে অভ্যন্তরীণ ব্যতিক্রমগুলি ব্যবহার করতে কিছুটা অপ্রত্যক্ষ মনে হয়।

ইন এই ব্লগ পোস্টে তারা কলিং (প্রতিফলন মাধ্যমে) করে সীমারেখা নম্বর (চেষ্টা ব্লক লাইন) সংরক্ষণ internalintance পদ্ধতি InternalPreserveStackTrace()উপর Exceptionবস্তু। তবে এর মতো প্রতিবিম্বটি ব্যবহার করা ভাল নয় (। নেট ফ্রেমওয়ার্ক internalকোনও দিন সতর্কতা ছাড়াই তাদের সদস্যদের পরিবর্তন করতে পারে )।


6

প্রাক্তন নিক্ষেপ এবং নিক্ষেপ মধ্যে পার্থক্য বুঝতে দিন। শুনেছি অনেক। নেট সাক্ষাত্কারে এই সাধারণ জিজ্ঞাসা করা হয়।

কেবল এই দুটি পদটির ওভারভিউ দেওয়ার জন্য, থ্রো এবং থ্রো প্রাক্তন উভয়ই ব্যতিক্রম কোথায় ঘটেছে তা বোঝার জন্য ব্যবহৃত হয়। থ্রো প্রাক্তন ব্যতিক্রমের স্ট্যাক ট্রেসকে পুনরায় লেখায় নির্বিশেষে যেখানে প্রকৃত নিক্ষেপ করা হয়েছে।

আসুন একটি উদাহরণ দিয়ে বুঝতে পারি।

আসুন প্রথম থ্রো বুঝতে পারি।

static void Main(string[] args) {
    try {
        M1();
    } catch (Exception ex) {
        Console.WriteLine(" -----------------Stack Trace Hierarchy -----------------");
        Console.WriteLine(ex.StackTrace.ToString());
        Console.WriteLine(" ---------------- Method Name / Target Site -------------- ");
        Console.WriteLine(ex.TargetSite.ToString());
    }
    Console.ReadKey();
}

static void M1() {
    try {
        M2();
    } catch (Exception ex) {
        throw;
    };
}

static void M2() {
    throw new DivideByZeroException();
}

উপরের ফলাফল নিচে।

সম্পূর্ণ শ্রেণিবিন্যাস এবং পদ্ধতির নাম দেখায় যেখানে প্রকৃতপক্ষে ব্যতিক্রম ছুঁড়েছে .. এটি এম 2 -> এম 2। লাইন নম্বর সহ

এখানে চিত্র বর্ণনা লিখুন

দ্বিতীয়ত .. থ্রো প্রাক্তন দ্বারা বুঝতে দিন। এম 2 পদ্ধতির ক্যাচ ব্লকে থ্রো প্রাক্তন দিয়ে কেবল প্রতিস্থাপন করুন। নীচের হিসাবে.

এখানে চিত্র বর্ণনা লিখুন

থ্রো প্রাক্তন কোডের আউটপুট নীচে হিসাবে রয়েছে ..

এখানে চিত্র বর্ণনা লিখুন

আপনি আউটপুটে পার্থক্যটি দেখতে পাচ্ছেন .. নিক্ষিপ্ত প্রাক্তন কেবল পূর্ববর্তী সমস্ত শ্রেণিবিন্যাসকে উপেক্ষা করে এবং স্ট্রোক ট্রেসটিকে লাইন / পদ্ধতিতে পুনরায় সেট করে যেখানে থ্রো প্রাক্তন লেখা আছে।


5

যখন তুমি কর throw ex , ছোঁড়া ব্যতিক্রমটি "আসল" হয়ে যায়। সুতরাং সমস্ত পূর্ববর্তী স্ট্যাক ট্রেস সেখানে হবে না।

আপনি যদি করেন throw, ব্যতিক্রম শুধু যায় রেখার নীচে যাবে এবং আপনি পুরো স্ট্যাক ট্রেস পাবেন।


4

না, এটি ব্যতিক্রমের জন্য আলাদা স্ট্যাক ট্রেস তৈরি করবে। শুধুমাত্র একটি ব্যবহারthrow ব্যতিক্রমী অবজেক্ট ছাড়াই করুনcatchহ্যান্ডলারের স্ট্যাক ট্রেস অপরিবর্তিত রেখে দেবে।

ব্যতিক্রমটি পুনর্বিবেচিত হবে কি না আপনি হ্যান্ডলি এক্সেপশন থেকে কোনও বুলিয়ান ফিরে আসতে চাইতে পারেন।


4

এমএসডিএন এর অর্থ :

একবার ব্যতিক্রম ছুঁড়ে ফেলা হলে, এটি বহন করে এমন তথ্যের একটি অংশ হ'ল স্ট্যাক ট্রেস। স্ট্যাক ট্রেস হল পদ্ধতি কল হায়ারার্কির একটি তালিকা যা সেই পদ্ধতিটি দিয়ে শুরু হয় যা ব্যতিক্রম ছুঁড়ে ফেলে এবং ব্যতিক্রমটি ধরার পদ্ধতিটির সাথে শেষ হয়। যদি থ্রো বিবৃতিতে ব্যতিক্রম উল্লেখ করে কোনও ব্যতিক্রম পুনরায় নিক্ষেপ করা হয় তবে স্ট্যাক ট্রেসটি বর্তমান পদ্ধতিতে পুনরায় আরম্ভ করা হবে এবং ব্যতিক্রমটি ছুঁড়ে ফেলেছে এমন মূল পদ্ধতির মধ্যে মেথড কলগুলির তালিকা এবং বর্তমান পদ্ধতিটি হারিয়ে গেছে। মূল স্ট্যাকের ট্রেস তথ্যটি ব্যতিক্রম সহ রাখতে, ব্যতিক্রম নির্দিষ্ট না করেই নিক্ষেপ বিবৃতিটি ব্যবহার করুন।


2

এখানে দেখুন: http://blog-mstechnology.blogspot.de/2010/06/throw-vs-throw-ex.html

নিক্ষেপ :

try 
{
    // do some operation that can fail
}
catch (Exception ex)
{
    // do some local cleanup
    throw;
}

এটি ব্যতিক্রম সহ স্ট্যাকের তথ্য সংরক্ষণ করে

এটিকে "রিথ্রো" বলা হয়

যদি নতুন ব্যতিক্রম ছুঁড়ে দিতে চান,

throw new ApplicationException("operation failed!");

প্রাক্তন নিক্ষেপ :

try
{
    // do some operation that can fail
}
catch (Exception ex)
{
    // do some local cleanup
    throw ex;
}

এটি ব্যতিক্রম সহ স্ট্যাকের তথ্য প্রেরণ করবে না

একে "ব্রেকিং দ্য স্ট্যাক" বলা হয়

যদি নতুন ব্যতিক্রম ছুঁড়ে দিতে চান,

throw new ApplicationException("operation failed!",ex);

0

এ সম্পর্কে আপনাকে আলাদা দৃষ্টিভঙ্গি দেওয়ার জন্য, থ্রো ব্যবহার বিশেষত কার্যকর যদি আপনি কোনও ক্লায়েন্টকে একটি এপিআই সরবরাহ করছেন এবং আপনি আপনার অভ্যন্তরীণ লাইব্রেরির জন্য ভার্বোজ স্ট্যাক ট্রেস তথ্য সরবরাহ করতে চান। এখানে নিক্ষেপ ব্যবহার করে আমি সিস্টেমের ক্ষেত্রে স্ট্যাক ট্রেসটি পেয়েছি File আমি যদি থ্রো প্রাক্তন ব্যবহার করি, তবে সেই তথ্যটি আমার হ্যান্ডলারের কাছে দেওয়া হবে না।

static void Main(string[] args) {            
   Method1();            
}

static void Method1() {
    try {
        Method2();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method1");             
    }
}

static void Method2() {
    try {
        Method3();
    } catch (Exception ex) {
        Console.WriteLine("Exception in Method2");
        Console.WriteLine(ex.TargetSite);
        Console.WriteLine(ex.StackTrace);
        Console.WriteLine(ex.GetType().ToString());
    }
}

static void Method3() {
    Method4();
}

static void Method4() {
    try {
        System.IO.File.Delete("");
    } catch (Exception ex) {
        // Displays entire stack trace into the .NET 
        // or custom library to Method2() where exception handled
        // If you want to be able to get the most verbose stack trace
        // into the internals of the library you're calling
        throw;                
        // throw ex;
        // Display the stack trace from Method4() to Method2() where exception handled
    }
}

-1
int a = 0;
try {
    int x = 4;
    int y ;
    try {
        y = x / a;
    } catch (Exception e) {
        Console.WriteLine("inner ex");
        //throw;   // Line 1
        //throw e;   // Line 2
        //throw new Exception("devide by 0");  // Line 3
    }
} catch (Exception ex) {
    Console.WriteLine(ex);
    throw ex;
}
  1. যদি সমস্ত লাইন 1, 2 এবং 3 তে মন্তব্য করা হয় - আউটপুট - অভ্যন্তরীণ প্রাক্তন

  2. যদি সমস্ত লাইন 2 এবং 3 তে মন্তব্য করা হয় - আউটপুট - অভ্যন্তরীণ প্রাক্তন সিস্টেম ev

  3. যদি সমস্ত লাইন 1 এবং 2 তে মন্তব্য করা হয় - আউটপুট - অভ্যন্তরীণ প্রাক্তন সিস্টেম x ধারণা: 0 দ্বারা ভাগ করুন ----

  4. যদি 1 এবং 3 এর সমস্ত লাইন মন্তব্য করা হয় - আউটপুট - অভ্যন্তরীণ প্রাক্তন সিস্টেম ev

প্রাক্তন থ্রো ক্ষেত্রে স্ট্যাকট্রেস পুনরায় সেট করা হবে;

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