কেন ক্যাচ দিয়ে একটি চেষ্টা ব্লকের অভ্যন্তরে ফেরত পাওয়া যাবে না?


97

নিম্নলিখিতটি ঠিক আছে:

try
{
    Console.WriteLine("Before");

    yield return 1;

    Console.WriteLine("After");
}
finally
{
    Console.WriteLine("Done");
}

finallyব্লক যখন পুরো জিনিস নির্বাহ সমাপ্ত হয়েছে (রান IEnumerator<T>সমর্থন IDisposableএই এমনকি যখন শুমার পরিত্যক্ত নিশ্চিত করার আগে এটি শেষ একটি উপায় প্রদান)।

তবে এটি ঠিক নয়:

try
{
    Console.WriteLine("Before");

    yield return 1;  // error CS1626: Cannot yield a value in the body of a try block with a catch clause

    Console.WriteLine("After");
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}

মনে করুন (যুক্তি দেখানোর জন্য) WriteLineচেষ্টা করুন ব্লকের মধ্যে একটি বা অন্য কল দ্বারা একটি ব্যতিক্রম ছুঁড়ে দেওয়া হয়েছে । catchব্লকে ফাঁসি কার্যকর করতে সমস্যা কী ?

অবশ্যই, ফলন ফেরতের অংশটি (বর্তমানে) কোনও কিছু ফেলতে অক্ষম, তবে কেন এটি আমাদের কোনও ঘের try/ আটকের catchআগে বা পরে ফেলে দেওয়া ব্যতিক্রমগুলি মোকাবেলা করা থেকে বিরত রাখবে yield return?

আপডেট: এখানে এরিক লিপার্টের একটি আকর্ষণীয় মন্তব্য রয়েছে - দেখে মনে হচ্ছে তাদের ইতিমধ্যে চেষ্টা / শেষ অবধি আচরণটি সঠিকভাবে প্রয়োগ করতে পর্যাপ্ত সমস্যা রয়েছে!

সম্পাদনা: এই ত্রুটিটির এমএসডিএন পৃষ্ঠাটি হ'ল: http://msdn.microsoft.com/en-us/library/cs1x15az.aspx । যদিও এটি ব্যাখ্যা করে না।


4
এরিক লিপার্টের মন্তব্যে সরাসরি লিঙ্ক: ব্লগস.এমএসডন.ল্ডনেউথিং
রোমান

দ্রষ্টব্য: আপনি নিজেই ক্যাচ ব্লকে উত্পাদন করতে পারবেন না :-(
সাইমন_উইভার

4
পুরানো নতুন লিঙ্কটি আর কাজ করে না।
সেবাস্তিয়ান রেডল

উত্তর:


50

আমি সন্দেহ করি এটি সম্ভাব্যতার চেয়ে বাস্তবতার বিষয়। আমার সন্দেহ হয় খুব খুব কম সময় হয়েছে যেখানে এই বিধিনিষেধটি আসলে এমন একটি সমস্যা যা চারপাশে কাজ করা যায় না - তবে সংকলকটিতে যুক্ত জটিলতা খুব তাৎপর্যপূর্ণ হবে।

এরকম কয়েকটি জিনিস রয়েছে যা আমি ইতিমধ্যে সম্মুখীন হয়েছি:

  • বৈশিষ্ট্য জেনেরিক হতে সক্ষম হচ্ছে না
  • এক্স এর জন্য এক্সওয়াই থেকে XY প্রাপ্তির অক্ষমতা (এক্সের নেস্টেড ক্লাস)
  • উত্পাদিত শ্রেণিতে জনসাধারণের ক্ষেত্রগুলি ব্যবহার করে ইট্রেটর ব্লক করে

এই প্রতিটি ক্ষেত্রে সংকলকটিতে অতিরিক্ত জটিলতার বিনিময়ে কিছুটা বেশি স্বাধীনতা অর্জন করা সম্ভব হবে। দলটি ব্যবহারিক পছন্দ করেছে, যার জন্য আমি তাদের প্রশংসা করেছিলাম - আমার পরিবর্তে 99.9% নির্ভুল সংকলক (হ্যাঁ, বাগ রয়েছে; আরও কিছুদিনের চেয়ে এসও-তে আমি ছুটে এসেছি) দিয়ে কিছুটা আরও নিয়ন্ত্রিত ভাষা চাই নমনীয় ভাষা যা সঠিকভাবে সংকলন করতে পারে না।

সম্পাদনা: এটি কেন সম্ভব হয় এটির একটি ছদ্ম প্রমাণ's

এটি বিবেচনা করুন:

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

এখন রূপান্তর:

try
{
    Console.WriteLine("a");
    yield return 10;
    Console.WriteLine("b");
}
catch (Something e)
{
    Console.WriteLine("Catch block");
}
Console.WriteLine("Post");

এর মধ্যে (সিউডো-কোডের সাজানো):

case just_before_try_state:
    try
    {
        Console.WriteLine("a");
    }
    catch (Something e)
    {
        CatchBlock();
        goto case post;
    }
    __current = 10;
    return true;

case just_after_yield_return:
    try
    {
        Console.WriteLine("b");
    }
    catch (Something e)
    {
        CatchBlock();
    }
    goto case post;

case post;
    Console.WriteLine("Post");


void CatchBlock()
{
    Console.WriteLine("Catch block");
}

একমাত্র নকলটি চেষ্টা / ব্লক ধরার সেটআপ করার ক্ষেত্রে - তবে এটি সংকলক অবশ্যই কিছু করতে পারে।

আমি হয়ত এখানে কিছু মিস করেছি - যদি তা হয় তবে দয়া করে আমাকে জানান!


11
ধারণাটির একটি ভাল প্রমাণ, তবে এই কৌশলটি বেদনাদায়ক হয়ে ওঠে (সি # সংকলক লেখকের চেয়ে কোনও সি # প্রোগ্রামারের পক্ষে সম্ভবত আরও বেশি) আপনি একবার usingএবং এর মতো জিনিসগুলির সাথে স্কোপগুলি তৈরি করা শুরু করেন foreach। উদাহরণস্বরূপ:try{foreach (string s in c){yield return s;}}catch(Exception){}
ব্রায়ান

"ট্রাই / ক্যাচ" এর সাধারণ শব্দার্থবিজ্ঞানগুলি বোঝায় যে কোনও ব্যতিক্রমের কারণে যদি চেষ্টা / ধরা ব্লকের কোনও অংশ বাদ দেওয়া হয় তবে যদি উপস্থিত থাকে তবে নিয়ন্ত্রণ একটি উপযুক্ত "ক্যাচ" ব্লকে স্থানান্তর করবে। দুর্ভাগ্যক্রমে, যদি কোনও ফলন ফেরতের "সময়কালে" ঘটে থাকে, তবে পুনরুদ্ধারকৃত ব্যক্তিদের ক্ষেত্রে ব্যতিক্রম হওয়ার কারণ যেখানে এটির নিষ্পত্তি হচ্ছে তাদের ক্ষেত্রে আলাদা করার উপায় নেই কারণ মালিক তার আগ্রহের সমস্ত ডেটা পুনরুদ্ধার করেছিলেন।
সুপারক্যাট

7
"আমার সন্দেহ হয় খুব খুব কম সময় হয়েছে যেখানে এই বিধিনিষেধটি আসলে এমন একটি সমস্যা যার আশেপাশে কাজ করা যায় না" এই জাতীয় কথা বলার মতো আপনাকে ব্যতিক্রমের দরকার নেই কারণ আপনি সাধারণত সি তে ব্যবহৃত ত্রুটি কোড ফেরত কৌশলটি ব্যবহার করতে পারেন অনেক বছর আগে. আমি স্বীকার করি প্রযুক্তিগত অসুবিধাগুলি তাৎপর্যপূর্ণ হতে পারে তবে yieldআমার মতে এটি স্প্যাগেটি কোডের কারণে আপনার চারপাশে কাজ করার জন্য লিখতে হবে বলে এটির তীব্রতা তীব্রভাবে সীমাবদ্ধ ।
jpmc26

@ jpmc26: না, এটি আসলে বলার মতো নয়। এটি আমাকে কখনই কামড়ায় তা আমি মনে করতে পারি না এবং আমি প্রচুর পরিমাণে পুনরাবৃত্তকারী ব্লক ব্যবহার করেছি। এটা তোলে সামান্য উপযোগিতা সীমিত yieldআইএমও - এটা থেকে দীর্ঘ পথ গুরুতরভাবে
জন স্কিটি

4
এই 'বৈশিষ্ট্য' আসলে কার্যসংক্রান্ত করার কিছু ক্ষেত্রে কিছু বরং অরুপ কোড প্রয়োজন, দেখতে stackoverflow.com/questions/5067188/...
namey

5

yieldএকটি পুনরাবৃত্ত সংজ্ঞা সমস্ত বিবৃতি একটি রাষ্ট্র মেশিনে একটি রাজ্যে রূপান্তরিত হয় যা কার্যকরভাবে একটি switchরাজ্যকে অগ্রসর করার জন্য একটি বিবৃতি ব্যবহার করে । যদি করেনি জন্য কোড জেনারেট yieldকরে দেখুন / ধরা মধ্যে বিবৃতির এটা নকল করতে হবে সবকিছু মধ্যে tryজন্য ব্লক প্রতিটি yield সময় প্রত্যেক অন্যান্য ব্যতীত বিবৃতি yieldযে ব্লক জন্য বিবৃতি। এটি সর্বদা সম্ভব হয় না, বিশেষত যদি একটি yieldবিবৃতি পূর্ববর্তী বর্ণনার উপর নির্ভর করে।


4
আমি মনে করি না যে আমি এটি কিনেছি। আমি মনে করি এটি সম্পূর্ণভাবে সম্ভব হবে - তবে খুব জটিল।
জন স্কিটি

4
সি # তে ব্লকগুলি চেষ্টা করুন / ধরার অর্থ পুনরায় প্রবেশকারী নয়। আপনি যদি এগুলি ভাগ করে নেন তবে ব্যতিক্রমের পরে মুভনেক্সট () কল করা এবং সম্ভবত অবৈধ অবস্থার সাথে চেষ্টা অবিরত চালিয়ে যাওয়া সম্ভব।
মার্ক সিডেড

2

আমি অনুমান করবো যে আপনি যখন কলকারীর কাছ থেকে রিটার্ন আনবেন তখন কল স্ট্যাকটি ক্ষত / অযাচিত হয়ে পড়েছে, কারণ চেষ্টা / ক্যাচ ব্লকের পক্ষে ব্যতিক্রমটি আসলে "ধরা" অসম্ভব হয়ে পড়ে। (কেননা ফলন ফেরতের ব্লকটি স্ট্যাকের মধ্যে নেই, যদিও তিনি পুনরাবৃত্তি ব্লকের সূচনা করেছেন)

আমি যে আইটিরেটর ব্লক সেটআপের কথা বলছি তার আইডিয়া পেতে এবং সেই পুনরায় ব্যবহারকারীর ব্যবহার করে একটি ফোরচ। ফোরচ ব্লকের ভিতরে কল স্ট্যাকটি কেমন দেখাচ্ছে তা পরীক্ষা করুন এবং তারপরে এটির পুনরায় চেষ্টা করুন / অবশেষে ব্লক করুন inside


আমি সি ++ এ স্ট্যাক আনওয়ানডিংয়ের সাথে পরিচিত, যেখানে সুযোগসীমার বাইরে থাকা স্থানীয় অবজেক্টগুলিতে ডেস্ট্রাক্টরদের ডাকা হয়। সি # এর সাথে সম্পর্কিত জিনিসটি চেষ্টা / শেষ পর্যন্ত হবে। ফলনের রিটার্ন যখন ঘটে তখন আনওয়াইন্ডিং ঘটে না। এবং চেষ্টা / ধরার জন্য ফলন ফেরতের সাথে ইন্টারঅ্যাক্ট করার দরকার নেই।
ড্যানিয়েল আরউইকার

কোনও পুনরুক্তিকারীকে লুপ করার সময় কল স্ট্যাকের কী হবে তা পরীক্ষা করে দেখুন এবং আমি কী বোঝাতে চাইছি তা বুঝতে হবে
Radu094

@ রডু094: না, আমি নিশ্চিত এটি সম্ভব হত। ভুলে যাবেন না যে এটি ইতিমধ্যে শেষ পর্যন্ত পরিচালনা করে যা অন্তত কিছুটা অনুরূপ।
জন স্কিটি 21

2

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

(আমি yield returnপুনরাবৃত্তিটি চালিত কোড দ্বারা "বাইরে থেকে" স্টেট মেশিনে স্টাফ করা একটি ব্যতিক্রম করার উপায় হওয়ার পক্ষে একটি দৃ desire় ইচ্ছা পোষণ করি But তবে আমার এটি চাওয়ার কারণগুলি যথেষ্ট অস্পষ্ট))

জনের জবাব সম্পর্কে আমার কাছে আসলে একটি জিজ্ঞাসা হ'ল ফলন প্রত্যাবর্তন অভিব্যক্তি নিক্ষেপ করা।

স্পষ্টতই ফলন ফিরতি 10 এত খারাপ নয়। তবে এটি খারাপ হবে:

yield return File.ReadAllText("c:\\missing.txt").Length;

সুতরাং পূর্ববর্তী চেষ্টা / ক্যাপ ব্লকের ভিতরে এটি মূল্যায়ন করা আরও বেশি অর্থবোধ করে না:

case just_before_try_state:
    try
    {
        Console.WriteLine("a");
        __current = File.ReadAllText("c:\\missing.txt").Length;
    }
    catch (Something e)
    {
        CatchBlock();
        goto case post;
    }
    return true;

পরবর্তী সমস্যা নেস্টেড চেষ্টা / ব্লক ধরা এবং ব্যতিক্রম পুনরায় উত্সাহিত করা হবে:

try
{
    Console.WriteLine("x");

    try
    {
        Console.WriteLine("a");
        yield return 10;
        Console.WriteLine("b");
    }
    catch (Something e)
    {
        Console.WriteLine("y");

        if ((DateTime.Now.Second % 2) == 0)
            throw;
    }
}
catch (Something e)
{
    Console.WriteLine("Catch block");
}
Console.WriteLine("Post");

তবে আমি নিশ্চিত যে এটি সম্ভব ...


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