ধরা এবং পুনরায় নিক্ষেপ করার জন্য সেরা অনুশীলনগুলি। নেট ব্যতিক্রম


284

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

try
{
    //some code
}
catch (Exception ex)
{
    throw ex;
}

বনাম:

try
{
    //some code
}
catch
{
    throw;
}

উত্তর:


262

স্ট্যাক ট্রেস সংরক্ষণের উপায় এটি ব্যবহারের মাধ্যমে throw;হয় valid

try {
  // something that bombs here
} catch (Exception ex)
{
    throw;
}

throw ex;মূলত সেই বিন্দু থেকে একটি ব্যতিক্রম ছোঁড়ার মতো, সুতরাং স্ট্যাক ট্রেস কেবল যেখানে আপনি throw ex;বিবৃতি জারি করছেন সেখানে যেতে হবে ।

মাইক এছাড়াও সঠিক, ব্যতিক্রম ধরে নিলে আপনাকে একটি ব্যতিক্রম (যা প্রস্তাবিত) পাস করতে দেয়।

কার্ল সেগুইনের পাশাপাশি তার প্রোগ্রামিং ই-বুকের ভিত্তিগুলিতে ব্যতিক্রম পরিচালনা করার ক্ষেত্রে একটি দুর্দান্ত রচনা রয়েছে যা একটি দুর্দান্ত পঠনযোগ্য।

সম্পাদনা: প্রোগ্রামিং পিডিএফ এর ফাউন্ডেশনের কাজের লিঙ্ক । "ব্যতিক্রম" এর জন্য কেবল পাঠ্যটি অনুসন্ধান করুন।


10
আমি এতটা নিশ্চিত নই যে সেই লিখনটি অপূর্ব কিনা, এটি সুপারিশ করে {// ...} ধরা (ব্যতিক্রম ব্যতিক্রম) ception নতুন ব্যতিক্রম ছোঁড়া (ex.Message + "অন্যান্য জিনিস"); } ভাল. সমস্যাটি হ'ল আপনি এই ব্যতিক্রমটিকে আর কোনও স্ট্যাক অবধি সামাল দিতে পুরোপুরি অক্ষম, যতক্ষণ না আপনি সমস্ত ব্যতিক্রমগুলি ধরেন, একটি বড় সংখ্যা-না (আপনি কি নিশ্চিত যে আপনি যে আউটআফ-মেমরিএক্সেপশনটি পরিচালনা করতে চান?)
ljs

2
@ লজস আপনার মন্তব্যের পর থেকে নিবন্ধটি পরিবর্তিত হয়েছে কারণ আমি যে কোনও বিভাগ তার প্রস্তাব দিই না। একেবারে বিপরীতে, তিনি এটি না করার কথা বলেছেন এবং জিজ্ঞাসা করেছেন যে আপনিও আউট অফ মেমরিএক্সসেপশন পরিচালনা করতে চান কিনা !?
রায়ানফায়েস্কটল্যান্ড

6
কখনও কখনও নিক্ষেপ; স্ট্যাক ট্রেস সংরক্ষণের জন্য যথেষ্ট নয়। এখানে একটি উদাহরণ https://dotnetfiddle.net/CkMFoX
Artavazd বালায়ান

4
অথবা ExceptionDispatchInfo.Capture(ex).Throw(); throw;। নেট +4.5 স্ট্যাকওভারফ্লো.
আলফ্রেড ওয়ালেস

@ অ্যালফ্রেডওয়্যালস সমাধানটি আমার পক্ষে নিখুঁতভাবে কাজ করেছে। চেষ্টা করুন {...} ধরা {নিক্ষেপ} স্ট্যাক ট্রেস সংরক্ষণ করেনি। ধন্যবাদ.
atownson

100

আপনি যদি প্রাথমিক ব্যতিক্রমের সাথে একটি নতুন ব্যতিক্রম ছুঁড়েন তবে আপনি প্রাথমিক স্ট্যাক ট্রেসও সংরক্ষণ করবেন ..

try{
} 
catch(Exception ex){
     throw new MoreDescriptiveException("here is what was happening", ex);
}

আমি নতুন ব্যতিক্রম ("বার্তা", প্রাক্তন) নিক্ষেপ করার চেষ্টা করি না কেন সর্বদা প্রস্থান করে এবং কাস্টম বার্তাকে উপেক্ষা করে। নিক্ষেপ নতুন এক্সেপশন ("বার্তা", প্রাক্তন-অভ্যন্তরীণ ধারণা) যদিও কাজ করে।
টড

যদি কোনও কাস্টম ব্যতিক্রম প্রয়োজন হয় না তবে কেউই AggregateException (.NET 4+) msdn.microsoft.com/en-us/library/…
নিকোস তসোকোস

AggregateExceptionকেবলমাত্র সম্মিলিত ক্রিয়াকলাপগুলির ব্যতিক্রমগুলির জন্য ব্যবহার করা উচিত। উদাহরণস্বরূপ, এটি সিএলআর এর ParallelEnumerableএবং Taskক্লাস দ্বারা নিক্ষেপ করা হয় । ব্যবহার সম্ভবত এই উদাহরণ অনুসরণ করা উচিত।
আলুয়ান হাদাদ

29

প্রকৃতপক্ষে, কিছু পরিস্থিতি রয়েছে যা throwস্ট্যাচট্রেস স্ট্যাকট্রেস তথ্য সংরক্ষণ করে না। উদাহরণস্বরূপ, নীচের কোডে:

try
{
  int i = 0;
  int j = 12 / i; // Line 47
  int k = j + 1;
}
catch
{
  // do something
  // ...
  throw; // Line 54
}

স্ট্যাকট্রেস নির্দেশ করবে যে লাইন 54 ব্যতিক্রম করেছে, যদিও এটি 47 লাইনে উত্থাপিত হয়েছিল।

Unhandled Exception: System.DivideByZeroException: Attempted to divide by zero.
   at Program.WithThrowIncomplete() in Program.cs:line 54
   at Program.Main(String[] args) in Program.cs:line 106

উপরের বর্ণিতটির মতো পরিস্থিতিতে, মূল স্ট্যাকট্রেসকে উপস্থাপন করার জন্য দুটি বিকল্প রয়েছে:

ব্যতিক্রম কল করা হচ্ছে I অভ্যন্তরীণ সংরক্ষণের স্ট্যাকট্রেস

এটি একটি বেসরকারী পদ্ধতি হওয়ায় এটি প্রতিবিম্ব ব্যবহার করে আহ্বান জানাতে হবে:

private static void PreserveStackTrace(Exception exception)
{
  MethodInfo preserveStackTrace = typeof(Exception).GetMethod("InternalPreserveStackTrace",
    BindingFlags.Instance | BindingFlags.NonPublic);
  preserveStackTrace.Invoke(exception, null);
}

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

কল করা ব্যতিক্রম Sসেটঅজেক্টডাটা

নীচের কৌশলটি আন্তঃ টিখি দ্বারা ইন সি # এর জবাব হিসাবে প্রস্তাব করেছিলেন , স্ট্যাক ট্রেস প্রশ্নটি না হারিয়ে আমি কীভাবে অভ্যন্তরীণ ধারণাটি পুনর্বার করতে পারি

static void PreserveStackTrace (Exception e) 
{ 
  var ctx = new StreamingContext  (StreamingContextStates.CrossAppDomain) ; 
  var mgr = new ObjectManager     (null, ctx) ; 
  var si  = new SerializationInfo (e.GetType (), new FormatterConverter ()) ; 

  e.GetObjectData    (si, ctx)  ; 
  mgr.RegisterObject (e, 1, si) ; // prepare for SetObjectData 
  mgr.DoFixups       ()         ; // ObjectManager calls SetObjectData 

  // voila, e is unmodified save for _remoteStackTraceString 
} 

যদিও, এটি পাবলিক পদ্ধতিতে নির্ভর করার সুবিধা রয়েছে কেবল এটি নিম্নলিখিত ব্যতিক্রমী নির্মাণকারীর উপরও নির্ভর করে (যা তৃতীয় পক্ষ দ্বারা বিকশিত কিছু ব্যতিক্রম বাস্তবায়ন করে না):

protected Exception(
    SerializationInfo info,
    StreamingContext context
)

আমার পরিস্থিতিতে আমাকে প্রথম পন্থাটি বেছে নিতে হয়েছিল, কারণ তৃতীয় পক্ষের লাইব্রেরি দ্বারা যে ব্যতিক্রমগুলি আমি ব্যবহার করছিলাম সেগুলি এই নির্মাণকারীর প্রয়োগ করে নি।


1
আপনি ব্যতিক্রমটি ধরতে পারেন এবং যে কোনও জায়গায় এই ব্যতিক্রমটি প্রকাশ করতে পারেন। তারপরে ব্যবহারকারীকে কী হয়েছে তা বোঝাতে একটি নতুন ছুঁড়ে ফেলুন। এইভাবে আপনি দেখতে পাচ্ছেন বর্তমান সময়ে ব্যতিক্রমটি ধরা পড়ার পরে কী ঘটেছিল, ব্যবহারকারী আসল ব্যতিক্রম কী তা নির্লিপ্ত করতে পারে।
ěŕxěŕ

2
.NET 4.5 এর সাথে একটি তৃতীয় আছে এবং - আমার মতে - ক্লিনার বিকল্প: এক্সসেপশনডিস্পাচআইনফো ব্যবহার করুন। ট্র্যাজেডিয়ানরা এখানে সম্পর্কিত প্রশ্নের উত্তর দেখুন: আরও তথ্যের জন্য stackoverflow.com/a/17091351/567000
সেরেন বোইসেন

20

আপনি যখন throw ex, মূলত একটি নতুন ব্যতিক্রম ছুঁড়ে ফেলছেন, এবং মূল স্ট্যাক ট্রেস তথ্যটি মিস করবেন। throwপছন্দসই পদ্ধতি।


13

থাম্বের নিয়ম হ'ল বেসিক Exceptionঅবজেক্টটি ধরা এবং নিক্ষেপ করা এড়ানো । এটি আপনাকে ব্যতিক্রম সম্পর্কে কিছুটা স্মার্ট হতে বাধ্য করে; অন্য কথায় আপনার কাছে একটি স্পষ্ট ক্যাচ থাকা উচিত SqlExceptionযাতে আপনার হ্যান্ডলিং কোডটি একটি দিয়ে কিছু ভুল না করে NullReferenceException

বাস্তব বিশ্বে যদিও, বেস ব্যতিক্রম ধরা এবং লগ করাও একটি ভাল অনুশীলন, তবে InnerExceptionsএটি যে কোনও কিছু পেতে পুরো জিনিসটি হাঁটতে ভুলবেন না ।


2
আমি মনে করি অ্যাপডোমাইন.কন্টেনডোমেন.অনহানডেলড এক্সেক্সশন এবং অ্যাপ্লিকেশন ব্যবহার করে লগিংয়ের উদ্দেশ্যে অপরিকল্পিত ব্যতিক্রমগুলি মোকাবেলা করা ভাল। থ্রেড এক্সসেপশন ব্যতিক্রম। বড় চেষ্টা করে Using ...} ক্যাচ (ব্যতিক্রম প্রাক্তন) Using ...} ব্লকগুলি সর্বত্র ব্যবহার করার অর্থ প্রচুর অনুলিপি। আপনি হ্যান্ডেল ব্যতিক্রমগুলি লগ করতে চান কিনা তা নির্ভর করে, সেই ক্ষেত্রে (কমপক্ষে সর্বনিম্ন) সদৃশ অনিবার্য হতে পারে।
ljs

প্লাস যারা অনুষ্ঠান মানে আপনি ব্যবহার না সব অপরিচালিত ব্যতিক্রম লগ ইন করুন, যেহেতু আপনি বড় ওল 'ব্যবহার করে দেখুন {...} ধরা (ব্যতিক্রম প্রাক্তন) {...} ব্লক ব্যবহার আপনি কিছু মিস্ হতে পারে।
ljs

10

আপনার সর্বদা "নিক্ষেপ;" ব্যবহার করা উচিত .NET- এ ব্যতিক্রমগুলি নতুন করে জানাতে

এটি উল্লেখ করুন, http://weblogs.asp.net/bhouse/archive/2004/11/30/272297.aspx

মূলত এমএসআইএল (সিআইএল) এর দুটি নির্দেশ রয়েছে - "নিক্ষেপ" এবং "পুনর্বিবেচনা":

  • সি # এর "নিক্ষেপ প্রাক্তন;" এমএসআইএল এর "নিক্ষেপ" তে সংকলিত হয়
  • সি # এর "নিক্ষেপ;" - এমএসআইএল "পুনর্বিবেচনা"!

মূলত আমি "থ্রো প্রাক্তন" স্ট্যাক ট্রেসকে ওভাররাইড করার কারণটি দেখতে পাচ্ছি।


লিঙ্কটি - ভাল, প্রকৃতপক্ষে লিঙ্কটিthrow ex; উত্সরিত উত্সটি - ভাল তথ্যে পূর্ণ, এবং কেন অনেকে মনে করেন যে পুনর্বিবেচনা করবে তার সম্ভাব্য অপরাধীকে নোট করে - জাভাতে, এটি করে! তবে আপনার এখানে গ্রেড এ উত্তর দেওয়ার জন্য সেই তথ্যটি অন্তর্ভুক্ত করা উচিত । (যদিও আমি এখনও ExceptionDispatchInfo.Captureজিউউইকডিসিওউজফডুসিইউ থেকে উত্তরটি ধরছি ।)
রুফিন

10

কেউই ExceptionDispatchInfo.Capture( ex ).Throw()কোনও সমভূমি এবং সমভূমির পার্থক্য ব্যাখ্যা করতে throwপারেনি, সুতরাং এটি এখানে। তবে কিছু লোক সমস্যাটি লক্ষ্য করেছেন throw

ধরা পড়া ব্যতিক্রমটি পুনর্বিবেচনার পুরো উপায়টি হ'ল ExceptionDispatchInfo.Capture( ex ).Throw()(কেবলমাত্র নেট .৪.৪ থেকে পাওয়া যায়)।

নীচে এটি পরীক্ষা করার জন্য প্রয়োজনীয় কেসগুলি রয়েছে:

1।

void CallingMethod()
{
    //try
    {
        throw new Exception( "TEST" );
    }
    //catch
    {
    //    throw;
    }
}

2।

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch( Exception ex )
    {
        ExceptionDispatchInfo.Capture( ex ).Throw();
        throw; // So the compiler doesn't complain about methods which don't either return or throw.
    }
}

3।

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch
    {
        throw;
    }
}

4।

void CallingMethod()
{
    try
    {
        throw new Exception( "TEST" );
    }
    catch( Exception ex )
    {
        throw new Exception( "RETHROW", ex );
    }
}

কেস 1 এবং কেস 2 আপনাকে একটি স্ট্যাক ট্রেস দেবে যেখানে CallingMethodপদ্ধতির উত্স কোড লাইন নম্বরটি লাইন নম্বরthrow new Exception( "TEST" )

তবে কেস 3 আপনাকে স্ট্যাক ট্রেস দেবে যেখানে CallingMethodপদ্ধতির সোর্স কোড লাইন নম্বরটি throwকলটির লাইন নম্বর । এর অর্থ throw new Exception( "TEST" )হ'ল লাইনটি যদি অন্য ক্রিয়াকলাপ দ্বারা ঘিরে থাকে তবে কোন লাইন নম্বরটিতে ব্যতিক্রমটি আসলে নিক্ষেপ করা হয়েছিল তা আপনার কোনও ধারণা নেই।

কেস 4 কেস 2 এর সাথে সমান কারণ মূল ব্যতিক্রমের লাইন সংখ্যাটি সংরক্ষণ করা হয়েছে তবে এটি সত্যিকারের পুনর্বিবেচনা নয় কারণ এটি আসল ব্যতিক্রমের ধরণের পরিবর্তন করে।


কখনও ব্যবহার না করার জন্য একটি সাধারণ ব্লার্ব যুক্ত করুন throw ex;এবং এটি তাদের সবার সেরা উত্তর।
এনএইচ।

8

কিছু লোক প্রকৃতপক্ষে খুব গুরুত্বপূর্ণ বিষয়টি মিস করেছে - 'থ্রো' এবং 'থ্রো প্রাক্তন' একই জিনিসটি করতে পারে তবে তারা আপনাকে কোনও রূপদানের একটি গুরুত্বপূর্ণ টুকরো দেয় না যা ব্যতিক্রম ঘটেছিল line

নিম্নলিখিত কোড বিবেচনা করুন:

static void Main(string[] args)
{
    try
    {
        TestMe();
    }
    catch (Exception ex)
    {
        string ss = ex.ToString();
    }
}

static void TestMe()
{
    try
    {
        //here's some code that will generate an exception - line #17
    }
    catch (Exception ex)
    {
        //throw new ApplicationException(ex.ToString());
        throw ex; // line# 22
    }
}

আপনি যখন একটি 'নিক্ষেপ' বা 'থ্রো প্রাক্তন' করেন তখন আপনি স্ট্যাকের সন্ধান পাবেন তবে # লাইনটি # 22 হতে চলেছে তাই কোন লাইনটি ব্যতিক্রমটি ঠিক ছুঁড়ে ফেলেছে তা বুঝতে পারবেন না (যদি আপনার কাছে কেবল 1 বা কয়েকটি না থাকে) চেষ্টা ব্লকে কোড লাইন)। আপনার ব্যতিক্রম প্রত্যাশিত লাইন # 17 পেতে আপনাকে মূল ব্যতিক্রম স্ট্যাক ট্রেস সহ একটি নতুন ব্যতিক্রম ছুঁড়ে ফেলতে হবে।


3

আপনি এটি ব্যবহার করতে পারেন:

try
{
// Dangerous code
}
finally
{
// clean up, or do nothing
}

এবং নিক্ষিপ্ত যে কোনও ব্যতিক্রমগুলি পরবর্তী স্তর পর্যন্ত বুদবুদ হবে যা তাদের পরিচালনা করে।


3

আমি অবশ্যই ব্যবহার করব:

try
{
    //some code
}
catch
{
    //you should totally do something here, but feel free to rethrow
    //if you need to send the exception up the stack.
    throw;
}

এটি আপনার স্ট্যাক সংরক্ষণ করবে।


1
২০০৮ সালে আমার অতীতকে ন্যায্য করার জন্য ওপি জিজ্ঞাসা করছিল কীভাবে স্ট্যাকটি সংরক্ষণ করা যায় - এবং ২০০৮ সালে আমি একটি সঠিক উত্তর দিয়েছি। আমার উত্তরটি যা অনুপস্থিত তা হ'ল প্রকৃতপক্ষে ক্যাচে কিছু করার অংশ।
কেভগ্রিফ

@ জনসন্ডার্স এটি সত্য যদি আপনি কেবল আগে কিছু না করেন তবেই throw; উদাহরণস্বরূপ, আপনি একটি নিষ্পত্তিযোগ্য পরিষ্কার করতে পারেন (যেখানে আপনি কেবলমাত্র একটি ত্রুটিতে কল করেন) এবং তারপরে ব্যতিক্রমটি ছুঁড়ে ফেলতে পারেন।
মেইরিওন হিউজেস

@ মিরিয়ান যখন আমি মন্তব্যটি লিখেছিলাম তখন ছুড়ে দেওয়ার আগে কিছুই ছিল না। যখন এটি যুক্ত করা হয়েছিল, আমি আপভোট করেছি, তবে মন্তব্যটি মুছলাম না।
জন স্যান্ডার্স

0

এফওয়াইআই আমি কেবল এটি পরীক্ষা করেছি এবং স্ট্রোকের ট্রেস 'থ্রো' দ্বারা প্রতিবেদন করা হয়েছে; সম্পূর্ণরূপে সঠিক স্ট্যাক ট্রেস নয়। উদাহরণ:

    private void foo()
    {
        try
        {
            bar(3);
            bar(2);
            bar(1);
            bar(0);
        }
        catch(DivideByZeroException)
        {
            //log message and rethrow...
            throw;
        }
    }

    private void bar(int b)
    {
        int a = 1;
        int c = a/b;  // Generate divide by zero exception.
    }

স্ট্যাক ট্রেস সঠিকভাবে ব্যতিক্রমের উত্সের দিকে নির্দেশ করে (উল্লিখিত লাইন নম্বর) তবে foo () এর জন্য রিপোর্ট করা লাইন নম্বরটি নিক্ষেপের লাইন; বিবৃতি, অতএব আপনি কোনটি কল () কল করতে ব্যর্থ হয়েছে তা বলতে পারবেন না।


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