Попробуйте / поймать + используя правильный синтаксис
Который из:
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.
}