using System; namespace TestUsing { public class MyResource : IDisposable { public void DoWork() { throw new ArgumentException("A"); } public void Dispose() { throw new ArgumentException("B"); } } public static class TestClass { public static void Test() { using (MyResource r = new MyResource()) { throw new ArgumentException("C"); r.DoWork(); } } } }
try { TestClass.Test(); } catch (Exception ex) { Console.WriteLine(ex.Message); }
پاسخ: برخلاف تصور (که احتمالا C است؛ چون قبل از فراخوانی متد DoWork سبب بروز استثناء شده است)، فقط B را در خروجی مشاهده خواهیم کرد!
و این دقیقا مشکلی است که در حین کار با کتابخانه iTextSharp برای اولین بار با آن مواجه شدم. روش استفاده متداول از iTextSharp به نحو زیر است:
using (var pdfDoc = new Document(PageSize.A4)) { //todo: ... }
و خلاصه نتایج هم این است:
اگر به ثبت جزئیات خطاهای سیستم اهمیت میدهید (یکی از مهمترین مزیتهای دات نت نسبت به بسیاری از فریم ورکهای مشابه که حداکثر خطای 0xABC12EF را نمایش میدهند)، از using استفاده نکنید! using در پشت صحنه به try/finally ترجمه میشود و بهتر است این مورد را دستی نوشت تا اینکه کامپایلر اینکار را به صورت خودکار انجام دهد.
در اینجا باز هم به یک سری کد تکراری try/finally خواهیم رسید و همانطور که در مباحث کاربردهای Action و Func در این سایت ذکر شد، میتوان آنرا تبدیل به کدهایی با قابلیت استفاده مجدد کرد. یک نمونه از پیاده سازی آنرا در این سایت «C# Using Blocks can Swallow Exceptions » میتوانید مشاهده کنید که خلاصه آن کلاس زیر است:
using System; namespace Guard { public static class SafeUsing { public static void SafeUsingBlock<TDisposable>(this TDisposable disposable, Action<TDisposable> action) where TDisposable : IDisposable { disposable.SafeUsingBlock(action, d => d); } internal static void SafeUsingBlock<TDisposable, T>(this TDisposable disposable, Action<T> action, Func<TDisposable, T> unwrapper) where TDisposable : IDisposable { try { action(unwrapper(disposable)); } catch (Exception actionException) { try { disposable.Dispose(); } catch (Exception disposeException) { throw new AggregateException(actionException, disposeException); } throw; } disposable.Dispose(); } } }
new Document(PageSize.A4).SafeUsingBlock(pdfDoc => { //todo: ... });