"ধরা, কখন" দিয়ে ব্যতিক্রম ধরা


97

আমি সি # তে এই নতুন বৈশিষ্ট্যটি জুড়ে এসেছি যা কোনও নির্দিষ্ট শর্ত পূরণ হওয়ার পরে একজন ক্যাচ হ্যান্ডলারকে সম্পাদন করতে দেয় allows

int i = 0;
try
{
    throw new ArgumentNullException(nameof(i));
}
catch (ArgumentNullException e)
when (i == 1)
{
    Console.WriteLine("Caught Argument Null Exception");
}

আমি কখন এটি কখন কার্যকর হতে পারে তা বোঝার চেষ্টা করছি।

একটি দৃশ্য এরকম কিছু হতে পারে:

try
{
    DatabaseUpdate()
}
catch (SQLException e)
when (driver == "MySQL")
{
    //MySQL specific error handling and wrapping up the exception
}
catch (SQLException e)
when (driver == "Oracle")
{
    //Oracle specific error handling and wrapping up of exception
}
..

তবে এটি আবার এমন কিছু যা আমি একই হ্যান্ডলারের মধ্যে করতে পারি এবং ড্রাইভারের ধরণের উপর নির্ভর করে বিভিন্ন পদ্ধতিতে প্রতিনিধিত্ব করতে পারি। এটি কি কোডটি বুঝতে সহজ করে তোলে? যুক্তিযুক্তভাবে না।

আরেকটি দৃশ্য যা আমি ভাবতে পারি তা হ'ল:

try
{
    SomeOperation();
}
catch(SomeException e)
when (Condition == true)
{
    //some specific error handling that this layer can handle
}
catch (Exception e) //catchall
{
    throw;
}

আবার এটি এমন কিছু যা আমি পছন্দ করতে পারি:

try
{
    SomeOperation();
}
catch(SomeException e)
{
    if (condition == true)
    {
        //some specific error handling that this layer can handle
    }
    else
        throw;
}

হ্যান্ডলারের সুনির্দিষ্ট ব্যবহারের কেসগুলি হ্যান্ডলারের তুলনায় হ্যান্ডলারের মতো এড়িয়ে যাওয়া এবং স্ট্যাক আনওয়াইন্ডিংয়ের তুলনায় 'ক্যাচ, যখন' ফিচারটি ব্যতিক্রম হ্যান্ডলিং দ্রুততর করে তোলে? এই বৈশিষ্ট্যটি আরও ভাল ফিট করে এমন কোনও নির্দিষ্ট ব্যবহারের কেস রয়েছে যা লোকেরা তখন একটি ভাল অনুশীলন হিসাবে গ্রহণ করতে পারে?


9
যদি whenব্যতিক্রমগুলি নিজেই অ্যাক্সেস করার প্রয়োজন হয় তবে এটি কার্যকর
টিম শ্মেলটার

4
তবে এটি হ্যান্ডলারটির মধ্যে ঠিক এমনভাবে অবরুদ্ধ হওয়ার মধ্যে আমরা কিছু করতে পারি। 'কিছুটা আরও সংগঠিত কোড' বাদে কি কোনও সুবিধা রয়েছে?
এমএস শ্রীকান্ত

4
তবে আপনি ইতিমধ্যে যে ব্যতিক্রমটি চান তা পরিচালনা করেছেন। আপনি যদি এটির অন্য কোথাও এটি ধরতে চান try..catch...catch..catch..finally?
টিম শেমলেটার

4
@ ব্যবহারকারী 3493289: সেই যুক্তি অনুসরণ করে, আমাদের ব্যতিক্রম হ্যান্ডলারগুলিতে অটোমেটিক টাইপ চেকের দরকার নেই: আমরা কেবল অনুমতি দিতে পারি catch (Exception ex), টাইপটি পরীক্ষা করতে পারি এবং throwঅন্যথায়। কিছুটা আরও সংগঠিত কোড (ওরফে কোড শোর এড়ানো) ঠিক এই কারণেই এই বৈশিষ্ট্যটি বিদ্যমান। (এটি অনেকগুলি বৈশিষ্ট্যের জন্য আসলে সত্য))
হেইনজি

4
@ টিমশ্মেলটার ধন্যবাদ উত্তর হিসাবে পোস্ট করুন এবং আমি এটি গ্রহণ করব। সুতরাং আসল পরিস্থিতিটি তখন হবে 'যদি পরিচালনা করার শর্তটি ব্যতিক্রমের উপর নির্ভর করে', তবে এই বৈশিষ্ট্যটি ব্যবহার করুন /
এমএস শ্রীকান্তকথ

উত্তর:


122

ক্যাপ ব্লক আপনাকে ইতিমধ্যে ব্যতিক্রমের ধরণের ফিল্টার করতে দেয় :

catch (SomeSpecificExceptionType e) {...}

whenদফা আপনি জেনেরিক এক্সপ্রেশন এই ফিল্টার প্রসারিত করতে পারেন।

সুতরাং, আপনি ব্যবহার whenক্ষেত্রে দফা যেখানে টাইপ ব্যতিক্রমের নির্ধারণ ব্যতিক্রম এখানে বা না নিয়ে নাড়াচাড়া করা উচিত কিনা তা স্বতন্ত্র যথেষ্ট নয়।


একটি সাধারণ ব্যবহারের ক্ষেত্রে ব্যতিক্রমের ধরণ যা আসলে একাধিক, বিভিন্ন ধরণের ত্রুটির জন্য মোড়ক

এখানে একটি কেস যা আমি আসলে ব্যবহার করেছি (ভিবিতে, ইতিমধ্যে বেশ কিছু সময়ের জন্য এই বৈশিষ্ট্যটি রয়েছে):

try
{
    SomeLegacyComOperation();
}
catch (COMException e) when (e.ErrorCode == 0x1234)
{
    // Handle the *specific* error I was expecting. 
}

একই জন্য SqlException, যার একটি ErrorCodeসম্পত্তিও রয়েছে। বিকল্প কিছু হবে:

try
{
    SomeLegacyComOperation();
}
catch (COMException e)
{
    if (e.ErrorCode == 0x1234)
    {
        // Handle error
    }
    else
    {
        throw;
    }
}

যা তর্কযোগ্যভাবে কম মার্জিত এবং স্ট্যাকের ট্রেসটি সামান্য বিরতি দেয়

এছাড়াও, আপনি একই চেষ্টা-ধরা-ব্লকে দু'বার একই ধরণের ব্যতিক্রম উল্লেখ করতে পারেন :

try
{
    SomeLegacyComOperation();
}
catch (COMException e) when (e.ErrorCode == 0x1234)
{
    ...
}
catch (COMException e) when (e.ErrorCode == 0x5678)
{
    ...
}

যা whenশর্ত ছাড়া সম্ভব হবে না ।


4
দ্বিতীয় পদ্ধতিরও এটি অন্যরকমভাবে ধরতে দেয় না catch, তাই না?
টিম শ্মেলেটার

@ টিমশ্মেলটার সত্য। আপনাকে একই ব্লকের সমস্ত COMException হ্যান্ডেল করতে হবে
হেইনজি

যদিও whenআপনাকে একাধিকবার একই ব্যতিক্রম টাইপ পরিচালনা করতে দেয়। আপনার উল্লেখ করা উচিত পাশাপাশি এটি একটি গুরুত্বপূর্ণ পার্থক্য। whenআপনি ছাড়া একটি সংকলক ত্রুটি পাবেন।
টিম শ্মেলেটার

4
যতদূর আমি উদ্বিগ্ন, "সংক্ষেপে:" নিম্নলিখিত অংশটি উত্তরের প্রথম লাইন হওয়া উচিত।
21:56

4
@ ব্যবহারকারী 3493289: যদিও প্রায়শই কুৎসিত গাধা কোডের ক্ষেত্রে এটি ঘটে। আপনি মনে করেন "আমি এই গোলযোগে প্রথমে থাকা উচিত নয়, কোডটি নতুন করে ডিজাইন করুন" এবং আপনিও মনে করেন "এই নকশাটিকে মার্জিতভাবে সমর্থন করার উপায় আছে, ভাষাটিকে নতুনভাবে ডিজাইন করুন"। এক্ষেত্রে আপনার ক্যাচ ক্লজগুলির সেটটি কতটা কুৎসিত হতে চান তার জন্য এক ধরণের প্রান্তিক প্রান্ত রয়েছে, সুতরাং কিছু পরিস্থিতি কিছুটা কুরুচিপূর্ণ করে তোলে যা আপনাকে আপনার দোরগোড়ায় আরও কাজ করতে দেয় :-)
স্টিভ জেসপ

38

রোজলিনের উইকি থেকে (জোর দেওয়া খনি):

ব্যতিক্রম ফিল্টারগুলি ধরা এবং পুনর্বিবেচনা করা পছন্দনীয় কারণ তারা স্ট্যাকটি ক্ষতিগ্রস্থ করে ফেলেছে । পরে যদি ব্যতিক্রম স্ট্যাকটি ডাম্প করার কারণ হয়ে থাকে তবে আপনি এটি দেখতে পারবেন যে এটি মূলত কোথা থেকে এসেছে, কেবল এটি শেষ স্থানের পরিবর্তে এটি পুনর্নির্মাণ হয়েছিল।

পার্শ্ব প্রতিক্রিয়াগুলির জন্য ব্যতিক্রম ফিল্টারগুলি ব্যবহার করা এটি "অপব্যবহার" এর একটি সাধারণ এবং স্বীকৃত ফর্ম; যেমন লগিং। তারা কোনও ব্যতিক্রমকে এর পথ অবরুদ্ধ না করে "উড়ন্ত" পরীক্ষা করতে পারে । এই ক্ষেত্রে, ফিল্টারটি প্রায়শই একটি মিথ্যা-রিটার্নিং সহায়ক ফাংশনে কল হবে যা পার্শ্ব প্রতিক্রিয়াগুলি কার্যকর করে:

private static bool Log(Exception e) { /* log it */ ; return false; }

… try { … } catch (Exception e) when (Log(e)) { }

প্রথম পয়েন্টটি প্রদর্শন করার মতো।

static class Program
{
    static void Main(string[] args)
    {
        A(1);
    }

    private static void A(int i)
    {
        try
        {
            B(i + 1);
        }
        catch (Exception ex)
        {
            if (ex.Message != "!")
                Console.WriteLine(ex);
            else throw;
        }
    }

    private static void B(int i)
    {
        throw new Exception("!");
    }
}

যদি আমরা এটি WinDbg- এ চালাই তবে ব্যতিক্রম না হওয়া অবধি এবং স্ট্যাকটি মুদ্রণ করে !clrstack -i -aআমরা এর কেবল ফ্রেমটি দেখতে পাব A:

003eef10 00a7050d [DEFAULT] Void App.Program.A(I4)

PARAMETERS:
  + int i  = 1

LOCALS:
  + System.Exception ex @ 0x23e3178
  + (Error 0x80004005 retrieving local variable 'local_1')

তবে, আমরা যদি প্রোগ্রামটি ব্যবহার করে পরিবর্তন করি when:

catch (Exception ex) when (ex.Message != "!")
{
    Console.WriteLine(ex);
}

আমরা স্ট্যাকটিতে এর ফ্রেমও দেখব B:

001af2b4 01fb05aa [DEFAULT] Void App.Program.B(I4)

PARAMETERS:
  + int i  = 2

LOCALS: (none)

001af2c8 01fb04c1 [DEFAULT] Void App.Program.A(I4)

PARAMETERS:
  + int i  = 1

LOCALS:
  + System.Exception ex @ 0x2213178
  + (Error 0x80004005 retrieving local variable 'local_1')

ক্র্যাশ ডাম্পগুলি ডিবাগ করার সময় সেই তথ্যটি খুব কার্যকর হতে পারে।


8
এটা আমাকে অবাক করে দেয়। না throw;(যেমন বিরোধিতা throw ex;) অক্ষত পাশাপাশি স্ট্যাক ছেড়ে? পার্শ্ব প্রতিক্রিয়া জিনিস জন্য +1। আমি নিশ্চিত যে আমি এটি অনুমোদন করেছি, তবে সেই কৌশলটি সম্পর্কে জানা ভাল।
হেইনজি

14
এটি ভুল নয় - এটি স্ট্যাক ট্রেসকে বোঝায় না - এটি স্ট্যাকটিকেই বোঝায়। আপনি যদি কোনও ডিবাগারে (WinDbg) স্ট্যাকের দিকে তাকান, এবং আপনি ব্যবহার করেছেন এমন কি throw;, স্ট্যাকটি খোলায় এবং আপনি প্যারামিটার মানগুলি হারাবেন।
এলি আরবেল

4
ডাম্পগুলি ডিবাগ করার সময় এটি অত্যন্ত কার্যকর হতে পারে।
এলি আরবেল

4
@ হেইনজি আমার উত্তরটি অন্য থ্রেডে দেখুন যেখানে আপনি দেখতে পাচ্ছেন যে throw;স্ট্যাকের ট্রেসটি একটু throw ex;পরিবর্তন করেছে এবং এটিকে অনেক পরিবর্তন করেছে।
জেপ্প স্টিগ নীলসেন

4
ব্যবহার throwস্ট্যাক ট্রেস সামান্য বিঘ্নিত করে। throwবিপরীতে হিসাবে ব্যবহার করার সময় লাইন নম্বরগুলি পৃথক হয় when
মাইক Zboray

7

যখন কোনও ব্যতিক্রম নিক্ষেপ করা হয়, ব্যতিক্রম হ্যান্ডলিংয়ের প্রথম পাসটি সনাক্ত করে যে স্ট্যাকটি আনওয়াইন্ড করার আগে ব্যতিক্রমটি কোথায় ধরা পড়বে ; যদি / যখন "ক্যাচ" অবস্থান চিহ্নিত করা হয়, সমস্ত "শেষ অবধি" ব্লকগুলি চালিত হয় (নোট করুন যদি কোনও ব্যতিক্রম একটি "অবশেষে" ব্লক থেকে অব্যাহত থাকে তবে পূর্ববর্তী ব্যতিক্রম প্রক্রিয়াটি পরিত্যাগ করা যেতে পারে)। এটি হয়ে গেলে, কোডটি "ধরা" এ পুনরায় প্রয়োগ শুরু করবে।

যদি "ফাংশন" এর অংশ হিসাবে মূল্যায়ন করা কোনও ফাংশনের মধ্যে যদি কোনও ব্রেকআপপয়েন্ট থাকে তবে কোনও স্ট্যাক আনওয়াইন্ডিং হওয়ার আগে সেই ব্রেকপয়েন্টটি কার্যকর করা স্থগিত করবে; বিপরীতে, একটি "ক্যাচ" এ ব্রেক ব্রেকপয়েন্ট সমস্ত finallyহ্যান্ডলার দৌড়ানোর পরে কেবল কার্যকর করা স্থগিত করবে ।

অবশেষে, যদি fooকলের 23 এবং 27 লাইন এবং 23 barলাইনে কল একটি ব্যতিক্রম ছুঁড়ে ফেলে যা foo57 লাইনে পুনরায় পুনরুত্থিত হয়, তবে স্ট্যাকের ট্রেসটি পরামর্শ করবে যে bar57 লাইন থেকে কল করার সময় ব্যতিক্রম ঘটেছে [পুনরায় অবস্থানের অবস্থান] , লাইন -23 বা লাইন -27 কলটিতে ব্যতিক্রম ঘটেছে কিনা সে সম্পর্কে কোনও তথ্য নষ্ট করে। whenপ্রথমে কোনও ব্যতিক্রম ধরা এড়াতে ব্যবহার করা এ জাতীয় ব্যাঘাত এড়ায়।

বিটিডাব্লু, একটি কার্যকর প্যাটার্ন যা সি # এবং ভিবি.এনইটি উভয় ক্ষেত্রে বিরক্তিকরভাবে বিশ্রী করে তোলে whenএকটি ভেরিয়েবল সেট করার জন্য একটি ধারাটির মধ্যে একটি ফাংশন কল ব্যবহার করা হয় যা একটি finallyফাংশনটি স্বাভাবিকভাবে সম্পন্ন হয় কিনা তা নির্ধারণের জন্য একটি ধারাটির মধ্যে ব্যবহার করা যেতে পারে যেখানে কোনও ফাংশন ক্ষেত্রে পরিচালনা করতে হয় ঘটে যাওয়া কোনও ব্যতিক্রম "সমাধান" করার কোনও আশা নেই তবে তবুও এর ভিত্তিতে পদক্ষেপ নিতে হবে। উদাহরণস্বরূপ, যদি কোনও ব্যতিক্রম কোনও ফ্যাক্টরি পদ্ধতির মধ্যে ফেলে দেওয়া হয় যা রিসোর্সগুলিকে এনক্যাপুলেট করে এমন কোনও বস্তু ফেরত দেবে বলে মনে করা হয়, যে কোনও সংস্থান গ্রহণ করা হয়েছিল সেগুলি মুক্তি দিতে হবে, তবে অন্তর্নিহিত ব্যতিক্রমটি কলারের কাছে ঘেঁষতে হবে। শব্দার্থকভাবে হ্যান্ডেল করার সবচেয়ে সহজ উপায় (যদিও সিনট্যাক্টিকভাবে নয়) একটি হ'লfinallyকোনও ব্যতিক্রম ঘটেছে কিনা তা ব্লক করুন এবং যদি তা হয় তবে অবজেক্টের পক্ষে অর্জিত সমস্ত সংস্থানকে ছেড়ে দিন যা আর ফিরে আসবে না। যেহেতু ক্লিনআপ কোড ব্যতিক্রমের কারণে যে কোনও শর্ত সমাধানের কোন আশা রাখে না, তাই এটি সত্যই হওয়া উচিত নয় catch, তবে কেবল কী হয়েছিল তা জানতে হবে। একটি ফাংশন কল করা:

bool CopySecondArgumentToFirstAndReturnFalse<T>(ref T first, T second)
{
  first = second;
  return false;
}

একটি whenদফার মধ্যে কারখানার কার্যকারিতাটি জেনে রাখা সম্ভব হয়েছিল যে কিছু ঘটেছিল।

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