попробуйте / поймать + используя правильный синтаксис

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
}
Xaqron
источник
7
Просто примечание: нужно быть осторожным, чтобы ловить только те исключения, которые действительно могут быть обработаны (исправлены), за исключением записи в журнал или их переноса.
Джон Сондерс
1
Пожалуйста, имейте в виду, что последнее утверждение также может вызвать исключение, как здесь} указано . using
Джулио Какчин
1
TIL, что отладчик (в VS) не будет вызывать метод dispose, если вы используете первый блок кода. Поскольку сам оператор using может генерировать исключение, он помогает мне использовать второй блок, чтобы гарантировать, что подразумеваемый finallyметод dispose.
ShooShoSha

Ответы:

98

Я предпочитаю второй. Также могут ловить ошибки, связанные с созданием объекта.

Джонатан Вуд
источник
11
Я не согласен с этим советом. Если вы ожидаете, что создание объекта вызовет ошибку, то любая обработка этого исключения должна выходить наружу. Если есть какой-то вопрос о том, куда должна идти обработка, то ожидаемое исключение должно быть чем-то другим - если только вы не выступаете за отлов любого случайного исключения, которое может или не может ожидаться, что является классическим анти-паттерном (вне обработчик исключений процесса или потока).
Джеффри Л Уитледж
1
@Джеффри: Подход, который я описал, хорошо послужил мне, и я делал это долгое время. Никто ничего не сказал о том, что создание объекта не удастся. Но, обернув операцию, которая может потенциально потерпеть неудачу в tryблоке, что позволяет вывести сообщение об ошибке в случае сбоя, программа теперь имеет возможность восстановить и сообщить пользователю.
Джонатан Вуд
Ваш ответ правильный , но продолжает предположение о том , что попытка / задвижка имеет быть там (сразу) во все времена.
Хенк Холтерман
17
Я думаю, что первое тоже имеет свои достоинства, рассмотрим транзакцию с БД, using( DBConnection conn = DBFactory.getConnection())которую необходимо откатить в случае возникновения исключительной ситуации. Мне кажется, что у обоих есть свое место.
wfoster
1
Это также будет ловить ошибки, связанные с удалением объекта.
Ахмад Ибрагим
39

Поскольку использование блока - это просто упрощение синтаксиса try / finally ( MSDN ), лично я хотел бы пойти на следующее, хотя я сомневаюсь, что он значительно отличается от вашего второго варианта:

MyClass myObject = null;
try {
  myObject = new MyClass();
  //important stuff
} catch (Exception ex) {
  //handle exception
} finally {
  if(myObject is IDisposable) myObject.Dispose();
}
chezy525
источник
4
Как вы думаете, почему добавление finallyблока предпочтительнее, чем usingутверждение?
Коди Грей
10
Добавление finallyблока, который удаляет объект IDisposable, - это то, что usingделает оператор. Лично мне нравится это вместо встроенного usingблока, потому что я думаю, что он более четко указывает, где все происходит, и что все это на одном и том же «уровне». Мне также нравится это больше, чем несколько встроенных usingблоков ... но это все только мои предпочтения.
chezy525
8
Если вы реализуете много обработок исключений, вам действительно нужно набирать текст! Это ключевое слово "using" существует уже некоторое время, и его значение мне совершенно ясно. И использование этого помогает сделать остальную часть моего кода более ясной, сводя количество беспорядка к минимуму.
Джонатан Вуд
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тела что-то может произойти, что не имеет прямого отношения к переменной in using, то я обертываю это другим tryдля этого конкретного исключения. Я редко использую Exceptionв моем catchES.

Но мне нравится, IDisposableи, usingхотя, возможно, я предвзят.

Schultz9999
источник
19

Если вашему оператору catch нужно получить доступ к переменной, объявленной в операторе using, то внутри - ваш единственный вариант.

Если вашему оператору catch требуется объект, на который ссылается использование, перед его удалением, то внутри - ваш единственный вариант.

Если ваш оператор catch выполняет действие неизвестной продолжительности, например, выводит сообщение пользователю, и вы хотели бы распоряжаться своими ресурсами до того, как это произойдет, тогда лучшим вариантом будет внешний.

Всякий раз, когда у меня есть сценарий, похожий на этот, блок try-catch обычно находится в другом методе дальше по стеку вызовов от использования. Для метода нетипично знать, как обрабатывать исключения, возникающие внутри него, вот так.

Таким образом, моя общая рекомендация - снаружи - далеко снаружи.

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

Оба являются допустимым синтаксисом. Это действительно сводится к тому, что вы хотите сделать: если вы хотите отлавливать ошибки, связанные с созданием / удалением объекта, используйте второй. Если нет, используйте первый.

Smashery
источник
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
}

Оба из которых довольно ясны; и затем это сокращает выбор между этими двумя аспектами, и зависит от того, какой вы хотите области действия объекта, где вы хотите обрабатывать ошибки создания экземпляра и когда вы хотите избавиться от него.

Джейсон С
источник