resource-cleanup از رابط IDispose استفاده میکند تا نشان دهد که وقتی دیگر به یک شیء نیازی نیست، منبع آن یا وضعیت دیگری از برنامه باید آزاد یا بازنشانی شود (و تکیه بر جمعکنندهی زباله این نتیجه را نمیدهد یا سطح لازم از کنترل را فراهم نمیکند) و اینکه متد IDisposable.Dispose() جای طبیعی چنین عملیات پاکسازی است.
سازهی دیگری هم وجود دارد به نام بلوک using که از دید فراخوانیکننده اجازه میدهد تمام مدیریت طول عمر منابع در یک دستور واحد جمع شود.
using (var file = new File("my_secrets"))
{
file.WriteSecret("xxxxxxx");
}
در مثال بالا، منابع سیستم فایل مرتبط با file وقتی از بلوک using خارج میشویم به سیستمعامل بازگردانده میشوند.
برای اینکه این الگو کار کند، متغیر در دستور using باید از نوع ارجاعی باشد که رابط IDisposable را پیادهسازی میکند و باید در متد Dispose() خود منابع را آزاد کند یا وضعیت برنامه را بازنشانی کند.
C# 8 بهبودی به این الگو اضافه میکند. دستور using میتواند در ابتدای یک بلوک قرار بگیرد.
using var drawingResource = some_provided_or_new_object;
try
{
drawingResource.DrawSomething();
}
catch (Exception)
{
throw;
}
توسعهدهندگان Java ممکن است این را معادلی برای مکانیزم مدیریت خودکار منابع بدانند که در Java 7 معرفی شد.
شما به کار روی سیستم ORM (نگاشت شیء-رابطهای) که در object-relational-mapping معرفی شد، بازگشتهاید.
تحلیل ما از نحوهی استفاده از ORM نشان میدهد که ۹۵٪ تراکنشها از درون یک متد فراخوانیکننده اجرا میشوند و تصمیم گرفته شده که مناسبتر است یک متد ORM واحد داشته باشیم که تراکنش را باز کند، بنویسد و ثبت کند.
پایگاهداده متدهای نمونهی زیر را دارد:
Database.BeginTransaction() یک تراکنش را روی پایگاهداده آغاز میکند.Database.Write(string data) داده را در جریان تراکنش روی پایگاهداده مینویسد. اگر دادهی نامعتبر دریافت کند، استثنا پرتاب میشود. اگر این متد بدون اینکه BeginTransaction() فراخوانی شده باشد صدا زده شود، استثنا پرتاب میشود. در صورت موفقیت، وضعیت داخلی پایگاهداده به DataWritten تغییر میکند.Database.EndTransaction() تراکنش را روی پایگاهداده ثبت میکند. اگر نتواند تراکنش را ببندد یا اگر Database.BeginTransaction() فراخوانی نشده باشد، ممکن است استثنا پرتاب کند.Database.Dispose() اگر در جریان یک تراکنش استثنا پرتاب شود، پایگاهداده را پاکسازی میکند. این کار وضعیت پایگاهداده را به Closed تغییر میدهد.متد Orm.Write() را طوری پیادهسازی کنید که تراکنشی روی پایگاهداده آغاز کند، دادهی ورودی را بنویسد و تراکنش را ثبت کند. همهی استثناها از جمله InvalidOperationException باید بدون ثبت لاگ یا هرگونه دخالت دیگری به فراخوانکننده منتقل شوند.
Database db = new Database();
Orm orm = new Orm(db);
orm.Write("good write");
// => database has an internal state of State.Closed
orm.Write("bad write");
// => an exception is thrown but database is left with an internal state of State.Closed
orm.Write("bad commit");
// => an exception is thrown but database is left with an internal state of State.Closed
چند ماه از معرفی Orm.Write() میگذرد و در تیم اختلاف نظر پیش آمده است. بسیاری از توسعهدهندگان ترجیح میدهند ORM هنگام پرتاب استثناها خودش خطاها را مدیریت کند و فقط نشانهای از موفقیت را به فراخوانکننده بازگرداند.
لطفاً متد Orm.WriteSafely() را طوری پیادهسازی کنید که تراکنشی روی پایگاهداده آغاز کند، دادهی ورودی را بنویسد و تراکنش را ثبت کند (مثل بالا). اگر نوشتن موفق باشد، باید true و در غیر این صورت false را بازگرداند. سعی نکنید استثنا را لاگ کنید.
Database db = new Database();
Orm orm = new Orm(db);
orm.WriteSafely("good write");
// => true
orm.WriteSafely("bad write");
// => false
orm.WriteSafely("bad commit");
// => false