নতুন। নেট কোর 3 এর দিকে স্যুইচ করার সময় IAsynsDisposable, আমি নিম্নলিখিত সমস্যাটিতে হোঁচট খেয়েছি।
সমস্যার মূল বিষয়: যদি DisposeAsyncকোনও ব্যতিক্রম ছুঁড়ে ফেলা হয়, তবে এই ব্যতিক্রমটি await usingব্লক-এর ভিতরে ফেলে দেওয়া কোনও ব্যতিক্রম লুকায় ।
class Program
{
static async Task Main()
{
try
{
await using (var d = new D())
{
throw new ArgumentException("I'm inside using");
}
}
catch (Exception e)
{
Console.WriteLine(e.Message); // prints I'm inside dispose
}
}
}
class D : IAsyncDisposable
{
public async ValueTask DisposeAsync()
{
await Task.Delay(1);
throw new Exception("I'm inside dispose");
}
}
যা ধরা পড়ছে তা হ'ল নিক্ষেপ করা হলে তা গ্রহণযোগ্যতা এবং নিক্ষেপ না করলে কেবল AsyncDisposeভিতরে থেকে ব্যতিক্রম ।await usingAsyncDispose
তবে আমি এটি অন্য উপায়ে পছন্দ করবো: await usingযদি সম্ভব হয় তবে ব্লক থেকে ব্যতিক্রম পাওয়া এবং DisposeAsync- await usingব্লকটি সফলভাবে শেষ হলেই ব্যতিক্রম ।
যুক্তি: কল্পনা করুন যে আমার ক্লাসটি Dকিছু নেটওয়ার্ক সংস্থান নিয়ে কাজ করে এবং কিছু নোটিফিকেশন রিমোটের জন্য সাবস্ক্রাইব করে। অভ্যন্তরীণ কোডটি await usingকিছু ভুল করতে পারে এবং যোগাযোগের চ্যানেলটিকে ব্যর্থ করতে পারে, এর পরে ডিসপোজ কোডটি কোডটি যোগাযোগের মাধ্যমে নিখুঁতভাবে বন্ধ করার চেষ্টা করে (যেমন, বিজ্ঞপ্তিগুলি থেকে সাবস্ক্রাইব করে) খুব ব্যর্থ হবে। তবে প্রথম ব্যতিক্রম আমাকে সমস্যা সম্পর্কে আসল তথ্য দেয় এবং দ্বিতীয়টি কেবল একটি গৌণ সমস্যা।
অন্য ক্ষেত্রে যখন মূল অংশটি দৌড়েছিল এবং নিষ্পত্তি ব্যর্থ হয়েছিল, আসল সমস্যাটি ভিতরেই রয়েছে DisposeAsync, সুতরাং ব্যতিক্রমটি DisposeAsyncপ্রাসঙ্গিক। এর অর্থ এই যে কেবলমাত্র সমস্ত ব্যতিক্রম ভিতরে দমন DisposeAsyncকরা ভাল ধারণা হওয়া উচিত নয়।
আমি জানি যে অ-অ্যাসিঙ্ক ক্ষেত্রে একই সমস্যা রয়েছে: ব্যতিক্রমটি ব্যতিক্রমগুলিকে finallyওভাররাইড করে try, তাই এটিকে নিক্ষেপ করার প্রস্তাব দেওয়া হয় না Dispose()। তবে নেটওয়ার্ক অ্যাক্সেস করার ক্লাসগুলি বন্ধ করার পদ্ধতিগুলিতে ব্যতিক্রমগুলি দমন করা মোটেই ভাল দেখাচ্ছে না।
নিম্নলিখিত সহায়িকার সাহায্যে সমস্যাটি নিয়ে কাজ করা সম্ভব:
static class AsyncTools
{
public static async Task UsingAsync<T>(this T disposable, Func<T, Task> task)
where T : IAsyncDisposable
{
bool trySucceeded = false;
try
{
await task(disposable);
trySucceeded = true;
}
finally
{
if (trySucceeded)
await disposable.DisposeAsync();
else // must suppress exceptions
try { await disposable.DisposeAsync(); } catch { }
}
}
}
এবং এটি পছন্দ করুন
await new D().UsingAsync(d =>
{
throw new ArgumentException("I'm inside using");
});
যা একধরণের কুৎসিত (এবং ব্যবহারের ব্লকের অভ্যন্তরে প্রারম্ভিক রিটার্নের মতো জিনিসগুলি অস্বীকার করে)।
await usingযদি সম্ভব হয় তবে একটি ভাল, প্রমিত সমাধান আছে ? ইন্টারনেটে আমার অনুসন্ধান এমনকি এই সমস্যাটি নিয়ে আলোচনা করে না।
CloseAsyncঅর্থ হ'ল এটি চালানোর জন্য আমার অতিরিক্ত সতর্কতা অবলম্বন করা উচিত। আমি যদি এটি কেবল using-ব্লকের শেষে রাখি তবে তা প্রাথমিক রিটার্ন ইত্যাদিতে এড়িয়ে যাবে। (এটিই আমরা ঘটতে চাই) এবং ব্যতিক্রমগুলি (এটিই আমরা ঘটতে চাইব)। তবে ধারণাটি আশাব্যঞ্জক বলে মনে হচ্ছে।
Disposeসবসময়ই ছিল "বিষয়গুলি ভুল হতে পারে: পরিস্থিতি উন্নতির জন্য আপনার যথাসাধ্য চেষ্টা করুন, তবে আরও খারাপ করবেন না", এবং কেন এর AsyncDisposeচেয়ে আলাদা হওয়া উচিত তা আমি দেখছি না ।
DisposeAsyncআপ পরিপাটি তার যথাসাধ্য চেষ্টা কিন্তু নিক্ষেপ করার অধিকার জিনিস। আপনি ইচ্ছাকৃত তাড়াতাড়ি রিটার্নের বিষয়ে কথা বলছিলেন , যেখানে ইচ্ছাকৃত তাড়াতাড়ি প্রত্যাবর্তন ভুল করে কোনও কলকে বাইপাস করতে পারে CloseAsync: এগুলি হ'ল অনেক কোডিং মানক দ্বারা নিষিদ্ধ।
Closeএই কারণেই আলাদা পদ্ধতি রয়েছে method এটি একইভাবে করা সম্ভবত বুদ্ধিমান:CloseAsyncজিনিসগুলি সুন্দরভাবে বন্ধ করার চেষ্টা করে এবং ব্যর্থতার দিকে ছুড়ে দেয়।DisposeAsyncশুধু এটি সেরা করে তোলে, এবং নিঃশব্দে ব্যর্থ হয়।