спробувати / catch + за допомогою правого синтаксису


189

Який:

using (var myObject = new MyClass())
{
   try
   {
      // something here...
   }
   catch(Exception ex)
   {
      // Handle exception
   }
}

АБО

try
{
   using (var myObject = new MyClass())
   {
      // something here...
   }
}
catch(Exception ex)
{
   // Handle exception
}

7
Лише зауваження: слід бути обережним лише для вилучення виключень, які фактично можуть бути оброблені (виправлені), за винятком ведення журналів або їх обгортання.
Джон Сондерс

1
Будь ласка , майте на увазі , що і останній }з usingзаяви може кинути виняток , як нагадав тут .
Джуліо Каччін

1
ПЕРЕКЛЮЧИТИ, що налагоджувач (у VS) не викличе метод розпорядження, якщо ви використовуєте перший блок коду. Оскільки саме оператор use може кинути виняток, мені допомагає використовувати другий блок, щоб забезпечити мається на увазі finallyпід назвою метод dispose.
ShooShoSha

Відповіді:


98

Я віддаю перевагу другому. Може також потрапляти помилки, пов'язані зі створенням об'єкта.


11
Я не згоден з цією порадою. Якщо ви очікуєте, що створення об’єкта призведе до помилки, то будь-яка обробка цього винятку повинна виходити назовні. Якщо виникає якесь питання щодо того, куди має йти обробка, то виняток, який очікується, повинен бути чимось іншим - якщо ви не виступаєте за вилучення випадкових винятків, які можуть бути, а може і не передбачати, що є класичним антидіаграмою (поза обробника Unhandled Handller Exceller (оброблення випуску) або потоку).
Джефрі Л Вітлідж

1
@Jeffrey: Підхід, який я описав, добре служив мені, і я цим займаюся давно. Ніхто нічого не говорив про те, що очікує, що створення об’єкта не вдасться. Але, обернувши операцію, яка потенційно може вийти з ладу в tryблоці, що дозволяє вивести повідомлення про помилку, якщо щось не вдалося, програма тепер має можливість відновити та повідомити користувача.
Джонатан Вуд

Ваша відповідь правильна, але продовжує припускати, що спроба / улов має бути там (негайно) постійно.
Хенк Холтерман

17
Я думаю, що спочатку є також заслуга, розгляньте транзакцію з базою даних, using( DBConnection conn = DBFactory.getConnection())яку потрібно буде повернути у випадку винятку. Мені здається, що обидва мають своє місце.
wfoster

1
Це також дозволить захопити помилки, пов’язані з утилізацією об'єкта.
Ахмад Ібрагім

39

Оскільки блок використання - це просто спрощення синтаксису спроби / нарешті ( MSDN ), особисто я б пішов із наступним, хоча я сумніваюся, що він значно відрізняється від вашого другого варіанту:

MyClass myObject = null;
try {
  myObject = new MyClass();
  //important stuff
} catch (Exception ex) {
  //handle exception
} finally {
  if(myObject is IDisposable) myObject.Dispose();
}

4
Чому ви вважаєте, що додавання finallyблоку є кращим до usingзаяви?
Коді Грей

10
Додавання finallyблоку, який розміщує об'єкт, що usingне використовується, - це те, що робиться у операторі. Особисто мені це подобається замість вбудованого usingблоку, тому що я вважаю, що він більш чітко визначає, де все відбувається, і що це все на одному "рівні". Мені також подобається це більше ніж декілька вбудованих usingблоків ... але все це лише на мою перевагу.
chezy525

8
Якщо ви застосовуєте багато обробку винятків, вам справді сподобається вводити текст! Це ключове слово "використання" існує вже деякий час, і це означає для мене цілком зрозуміло. А його використання допомагає зробити решту мого коду більш чітким, зводячи кількість непотрібності до мінімуму.
Джонатан Вуд

2
Це неправильно. Об'єкт повинен бути екземпляром за межами tryзаяви, щоб він міг бути розміщений в finallyоператорі; в іншому випадку це призведе до помилки компілятора: "Використання непризначеної локальної змінної 'myObject'"
Стів Конвес

3
Технічно це також не складе. Cannot assign null to implicitly-typed local variable;) Але я знаю, що ви маєте на увазі, і особисто я вважаю за краще це вкладення блоку.
Коннелл

20

Це залежить. Якщо ви використовуєте Windows Communication Foundation (WCF), using(...) { try... }він не буде працювати належним чином, якщо проксі-сервер у usingвикладі знаходиться у стані винятку, тобто розміщення цього проксі-сервера спричинить інший виняток.

Особисто я вірю в мінімальний підхід до обробки, тобто обробляти єдиний виняток, про який ви знаєте в момент виконання. Іншим словом, якщо ви знаєте, що ініціалізація змінної в usingможе кинути певний виняток, я завершу її try-catch. Так само, якщо всередині usingтіла може статися щось, що не пов'язане безпосередньо зі змінною в using, я обертаю її іншою tryдля цього конкретного винятку. Я рідко використовую Exceptionв своїх catchес.

Але мені це подобається IDisposableі usingхоча я, можливо, упереджений.


19

Якщо у вашій заяві вилову потрібно отримати доступ до змінної, оголошеної у використовуваному операторі, то всередині це ваш єдиний варіант.

Якщо у вашій заяві про вилов потрібен об'єкт, на який посилається у використанні, перед тим, як він буде утилізований, то всередині це ваш єдиний варіант.

Якщо у вашій заяві про улов трапляються дії невідомої тривалості, як-от показ повідомлення користувачеві, і ви хочете розпоряджатися своїми ресурсами до того, як це станеться, тоді зовні - ваш найкращий варіант.

Кожен раз, коли у мене є сценарій, подібний до цього, блок пробного лову зазвичай є іншим способом, що надалі збільшує стек виклику від використання. Для методу не типово знати, як поводитися з винятками, що трапляються всередині нього.

Тож мої загальні рекомендації знаходяться назовні - шлях зовні.

private void saveButton_Click(object sender, EventArgs args)
{
    try
    {
        SaveFile(myFile); // The using statement will appear somewhere in here.
    }
    catch (IOException ex)
    {
        MessageBox.Show(ex.Message);
    }
}

10

Обидва є дійсним синтаксисом. Це дійсно зводиться до того, що ви хочете зробити: якщо ви хочете виявити помилки, пов’язані зі створенням / розпорядженням об'єктом, використовуйте друге. Якщо ні, використовуйте перший.


8

Існує одна важлива річ , яку я буду називати тут: Перший з них буде НЕ зловити будь-виключення , що виникає з - за виклику MyClassконструктора.


3

З C # 8.0 я вважаю за краще використовувати другий такий же, як і цей

public class Person : IDisposable
{
    public Person()
    {
        int a = 0;
        int b = Id / a;
    }
    public int Id { get; set; }

    public void Dispose()
    {
    }
}

і потім

static void Main(string[] args)
    {

        try
        {
            using var person = new Person();
        }
        catch (Exception ex) when
        (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
        ex.TargetSite.MemberType == System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Constructor Person");
        }
        catch (Exception ex) when
       (ex.TargetSite.DeclaringType.Name == nameof(Person) &&
       ex.TargetSite.MemberType != System.Reflection.MemberTypes.Constructor)
        {
            Debug.Write("Error Person");
        }
        catch (Exception ex)
        {
            Debug.Write(ex.Message);
        }
        finally
        {
            Debug.Write("finally");
        }
    }

1

Якщо об’єкт, який ви ініціалізуєте в блоці Using (), може викинути будь-який виняток, тоді вам слід перейти до другого синтаксису, інакше обидва однаково дійсні.

У моєму сценарії я повинен був відкрити файл, і я передав filePath в конструкторі об'єкта, який я ініціалізував у блоці Using (), і він може викинути виняток, якщо filePath неправильний / порожній. Тож у цьому випадку другий синтаксис має сенс.

Мій зразок коду: -

try
{
    using (var obj= new MyClass("fileName.extension"))
    {

    }
}
catch(Exception ex)
{
     //Take actions according to the exception.
}

1

Починаючи з C # 8.0 , ви можете спростити usingоператори за певних умов, щоб позбутися від вкладеного блоку, а потім він просто застосовується до блоку, що додається.

Тож ваші два приклади можна звести до:

using var myObject = new MyClass();
try
{
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

І:

try
{
   using var myObject = new MyClass();
   // something here...
}
catch(Exception ex)
{
   // Handle exception
}

Обидва вони досить чіткі; і тоді це зводить вибір між цими двома питаннями того, яким ви хочете бути сферою дії об'єкта, де ви хочете обробляти помилки інстанції та коли ви хочете їх утилізувати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.