Чи бувають ситуації, коли доречно використовувати try-finallyблок без catchблоку?
Відповіді:
Ви використовували б його, щоб переконатися, що деякі дії відбуваються після tryвмісту або щодо винятку, але коли ви не хочете використовувати цей виняток.
Щоб зрозуміти, це не приховує винятків. finallyБлок виконується перед виняток передається в стек викликів.
Ви також ненавмисно використовуєте його, коли використовуєте usingключове слово, оскільки це компілюється у try-finally(не точне перетворення, але для аргументу воно досить близько).
try
{
TrySomeCodeThatMightException();
}
finally
{
CleanupEvenOnFailure();
}
Запуск коду finallyне гарантовано запущений, однак той випадок, коли він не гарантований, є досить суворим - я навіть не пам’ятаю його. Все, що я пам’ятаю, це те, що якщо ви в такому випадку, дуже великі шанси, що не запуск finallyне є вашою найбільшою проблемою :-) так що в основному не потійте.
Оновлення від Tobias: finally не запускатиметься, якщо процес буде вбито.
Оновлення від Педді: умови, коли нарешті не виконується при спробі
Найпоширеніший приклад, який ви можете побачити, - це утилізація підключення до бази даних або зовнішнього ресурсу, навіть якщо код не вдається:
using (var conn = new SqlConnection("")) // Ignore the fact we likely use ORM ;-)
{
// Do stuff.
}
Компілюється в щось на зразок:
SqlConnection conn;
try
{
conn = new SqlConnection("");
// Do stuff.
}
finally
{
if (conn != null)
conn.Dispose();
}
usingеквівалентно try-finally. Ви будете використовувати лише try-finallyтоді, коли захочете провести чистку всередині finallyі не дбаєте про виняток.
Найкращий підхід буде
try
{
using(resource)
{
//Do something here
}
}catch(Exception)
{
//Handle Error
}
Виконавши це навіть очищення, викликане usingвідмовами, ваш код не дасть збою.
Є деякі умови, коли finallyне вдасться виконати.
StackOverflowExceptionабо ExecutingEngineException.Сподіваюся, це відповідає на ваші сумніви.
Якщо у вас є, наприклад, некерований ресурс, який ви створюєте та використовуєте в блоці try, ви можете використовувати блок нарешті, щоб забезпечити випуск цього ресурсу. Блок нарешті завжди буде виконаний, незважаючи на те, що відбувається (наприклад, винятки) у блоці try.
Наприклад, оператор lock (x) насправді такий:
System.Threading.Monitor.Enter(x);
try { ... }
finally
{
System.Threading.Monitor.Exit(x);
}
Блок нарешті завжди буде викликаний, щоб гарантувати звільнення ексклюзивного блокування.
Гарне пояснення з використанням коду:
void MyMethod1()
{
try
{
MyMethod2();
MyMethod3();
}
catch(Exception e)
{
//do something with the exception
}
}
void MyMethod2()
{
try
{
//perform actions that need cleaning up
}
finally
{
//clean up
}
}
void MyMethod3()
{
//do something
}
Якщо або MyMethod2, або MyMethod3 видають виняток, це буде виявлено MyMethod1. Однак, код у MyMethod2 повинен запустити код очищення, наприклад, закривши підключення до бази даних, перш ніж виняток буде передано MyMethod1.
Вам потрібен блок нарешті, коли незалежно від того, які (якщо такі є) винятки були схоплені або навіть якщо жоден не спійманий, ви все одно хочете виконати якийсь код до виходу блоку. Наприклад, ви можете закрити відкритий файл.
Див. Також спробуй нарешті
try / нарешті: коли ви не хочете обробляти будь-які винятки, але хочете переконатись, що виконуються певні дії, незалежно від того, чи викликає виняток викликаний код.
Я нічого не знаю про C #, але, здається, все, що ви могли б зробити за допомогою спроби, нарешті, ви могли б зробити більш елегантно за допомогою оператора using . С ++ навіть не має остаточного результату в результаті свого RAII .
try, то зменшуєте його в a finally, ви не можете цього робити в usingоператорі.
Try-[Catch]-Finallyобробляє, не створюючи такого об’єкта.
usingале ви не можете зробити ковдру, як у вас є. Знову ж таки, це визначає проблему шляхом рішення, яке для мене є зворотним.
Ось ситуація, коли ви можете скористатися спробою нарешті: коли ви зазвичай використовуєте оператор using, але не можете, оскільки ви викликаєте метод за допомогою рефлексії.
Це не спрацює
using (objMsg = Activator.CreateInstance(TypeAssist.GetTypeFromTypeName("omApp.MessagingBO")))
{
}
натомість використовувати
object objMsg = null;
try
{
objMsg
= Activator.CreateInstance(TypeAssist.GetTypeFromTypeName("myAssembly.objBO"));
strResponse = (string)objMsg.GetType().InvokeMember("MyMethod", BindingFlags.Public
| BindingFlags.Instance | BindingFlags.InvokeMethod, null, objMsg,
new object[] { vxmlRequest.OuterXml });
}
finally
{
if (objMsg!=null)
((IDisposable)objMsg).Dispose();
}
Подивіться на таке посилання: /software/131397/why-use-try-finally-without-a-catch-clause
Це залежить від архітектури вашої програми та операції, яку ви виконуєте в блоці.
1. ми можемо використовувати блок try без catch, але ми повинні використовувати catch / нарешті, будь-який з них. 2.Ми не можемо використовувати лише блок спроб.
tryтаfinallyяк " твердження " спробувати остаточно ".