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

Который из:

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 ответов

Решение

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

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

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

Это зависит. Если вы используете Windows Communication Foundation (WCF), using(...) { try... } не будет работать правильно, если прокси в using оператор находится в состоянии исключения, т.е. удаление этого прокси вызовет другое исключение.

Лично я верю в минимальный подход к обработке, т. Е. Обрабатывать только те исключения, которые вам известны в момент исполнения. Другими словами, если вы знаете, что инициализация переменной в using может бросить конкретное исключение, я обернуть его try-catch, Аналогично, если внутри using тело может что-то случиться, что не имеет прямого отношения к переменной в usingпотом оборачиваю другим try для этого конкретного исключения. Я редко пользуюсь Exception в моем catchэс.

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

Если вашему оператору 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);
    }
}

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

Здесь я упомяну одну важную вещь: первая не поймет никаких исключений, возникающих из вызова MyClass конструктор.

Начиная с 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
}

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

Из 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");
        }
    }

Если объект, который вы инициализируете в блоке Using(), может выдать какое-либо исключение, вам следует перейти ко второму синтаксису, в противном случае оба одинаково действительны.

В моем сценарии мне пришлось открыть файл, и я передавал filePath в конструкторе объекта, который я инициализировал в блоке Using(), и он мог выдать исключение, если filePath неправильный / пустой. Так что в этом случае второй синтаксис имеет смысл.

Мой пример кода:-

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

    }
}
catch(Exception ex)
{
     //Take actions according to the exception.
}
Другие вопросы по тегам