Ответ 1
Нет, это выглядит отлично. Экземпляр вашего бара будет удален до того, как вы попадете в блок catch.
MSDN рекомендует помещать любые экземпляры классов, которые реализуют IDisposable
в блок using
. Или, альтернативно, если он создается в блоке try-catch
, тогда Dispose
в Finally
.
Существуют ли какие-либо проблемы с использованием блока using
в блоке try-catch
, например, так?
try
{
using (Foo bar = new Foo())
{
bar.doStuff();
}
}
catch (Exception e)
{
//vomit e
}
Конечно, я могу просто вызвать Dispose
в блоке Finally
, но я новичок в программировании, и мне просто интересно узнать, подходит ли что-то подобное, или если кто-то ударит меня затылок и кричать на меня, что я Doing-It-Wrong™
.
Или, скорее, меня больше интересует, почему это было бы неправильно, если бы это было.
Нет, это выглядит отлично. Экземпляр вашего бара будет удален до того, как вы попадете в блок catch.
Это... барабан... абсолютно нормально.
Единственная проблема заключается в том, что вы не должны использовать catch (Exception)
, но поймать конкретные ошибки, которые вас интересуют (даже если это только пример), но это не влияет на using
. Фактически, единственная причина, по которой вы ставите using
вне блока try
, - это то, что вы хотите продолжить что-то делать с bar
, не связанным с кодом, который не удался - в противном случае, чтобы область была как можно меньше как правило, хорошая идея.
Это нормально, но вы потеряли доступ к объекту, который вызвал бы исключение в исключении.
И ловить общие исключения не считается хорошей практикой
Foo bar = null;
try
{
bar = new Foo();
bar.doStuff();
}
catch (IndexOutOfRangeException e)
{
//vomit e
Debug.WriteLine(e.msg);
if(bar == null)
Debug.WriteLine("bar = new Foo() failed ");
else
Debug.WriteLine("bar fail ID = " + bar.ID);
}
catch (Exception e)
{
// ...
// unless you are going to handle it gracefully you should rethrow it
}
finally
{
if(bar != null) bar.Dispose();
}
Ваш примерный код лишний. Using()
документация:
A, используя инструкцию вида
using (ResourceType resource = expression)
Оператор соответствует одному из двух возможных расширений. Когда ResourceType - тип значения, расширение
{
ResourceType resource = expression;
try {
statement;
}
finally {
((IDisposable)resource).Dispose();
}
}
В противном случае, когда ResourceType является ссылочным типом, расширение
{
ResourceType resource = expression;
try {
statement;
}
finally {
if (resource != null) ((IDisposable)resource).Dispose();
}
}
В любом расширении переменная ресурса доступна только для чтения во встроенной инструкции.
В конечном итоге ваш код будет выглядеть примерно так:
try
{
Foo bar = new Foo()
try
{
bar.doStuff();
}
finally
{
if (bar != null) ((IDisposable)bar).Dispose();
}
}
catch (Exception e)
{
//vomit e
}
Нет реальной причины для двух утверждений try. Это не неправильный код, он просто лишний в контексте нескольких операторов try. Кажется, вы задаете вопрос о Disposing
объекта. В этом контексте он избыточен. Если вы также обеспокоены тем, что конструктор объектов выбрасывает исключение, очевидно, что это будет необходимо.
Есть ли проблемы с использованием используемого блока в блоке try-catch, например?
Нет, я пишу ваш пример все время.
Конечно, я могу просто вызвать Dispose в блоке finally,
Сорт, конструктор должен вызываться вне try/catch, иначе переменная будет недоступна к моменту достижения вами блока finally
справедливы:
var foo = new bar();
try
{
}
finally
{
foo.Dispose();
}
недопустим:
try
{
var foo = new bar();
}
finally
{
foo.Dispose();
}
Нет, это нормально, но если вы хотите получить доступ к bar
во время catch
, вам понадобится внутренний try catch
:
try
{
using (Foo bar = new Foo())
{
try
{
bar.doStuff();
}
catch (Exception e)
{
//vomit e, with bar available.
}
}
}
catch (Exception e)
{
//vomit e, relating to a problem during creation of Foo.
}
или, как было предложено в комментариях, разложить внутренний блок на новый метод.