Подтвердить что ты не робот

Поймать исключения в блоке использования за пределами используемого блока - что лучше?

Есть ли разница между этими элементами куска кода и какой подход лучше.

try
{
    using()
    { 
      //Do stuff
    }
}
catch
{
    //Handle exception
}


using()
{
    try
    {
         //Do stuff
    }
    catch
    {
        //Handle exception
    }
}
4b9b3361

Ответ 1

Существуют различия, но это сводится к тому, что используемый блок создает собственные блоки try и scope.

try
{
    using(IDisposable A = GetDisposable())
    { 
      //Do stuff
    }
}
catch
{
    //Handle exception
    // You do NOT have access to A
}


using(IDisposable A = GetDisposable())  //exception here is uncaught
{
    try
    {
         //Do stuff
    }
    catch
    {
        //Handle exception
        // You DO have access to A
    }
}

Ответ 2

Есть разница между этими блоками. Во втором случае исключение не будет поймано, если оно выбрано в строке using() (например, создание экземпляра объекта IDisposable и конструктор генерирует исключение). Какой из них лучше будет зависеть от ваших конкретных потребностей.

Ответ 3

Да. В первом случае ресурс, который вы используете, будет удален до того, как будет выполнен блок catch. В дальнейшем он будет удален позже. Более того, оператор "foo" не входит в объем предложения catch. Блок "использования" является почти синтаксическим сахаром, так что

using (foo)
{
}

является

try
{
  foo;
}
finally
{
  foo.Dispose();
}

Какое поведение "лучше" не очевидно без контекста.

Ответ 4

В конечном итоге вы можете комбинировать оба метода для преодоления обоих недостатков:

IFoo f;
try{
  f = new Foo();
  f.Bar();
catch{
  // Do something exceptional with f
} finally{
  if(f != null) f.Dispose();
}

Ответ 5

Предполагаю, вы имеете в виду:

using (var x = new Y(params))
{
}

В обоих случаях? Тогда очевидным отличием является область действия x. Во втором случае вы можете получить доступ к x в предложении catch. В первом случае вы не смогли.

Я также воспользуюсь возможностью, чтобы напомнить вам не "обрабатывать" исключение, если вы не можете действительно что-то сделать. Это включает в себя ведение журнала исключения, что было бы нормально, если только среда, в которой вы работаете, выполняет регистрацию для вас (как это делает ASP.NET 2.0 по умолчанию).

Ответ 6

Как упоминалось выше, только первый метод будет ловить исключения в инициализации объекта IDisposable и будет иметь объект в области для блока catch.

Кроме того, порядок операций для блоков catch и finally будет перевернут в зависимости от их вложенности. Возьмем следующий пример:

public class MyDisposable : IDisposable
{
    public void Dispose()
    {
        Console.WriteLine("In Dispose");
    }

    public static void MethodOne()
    {
        Console.WriteLine("Method One");
        using (MyDisposable disposable = new MyDisposable())
        {
            try
            {
                throw new Exception();
            }
            catch (Exception ex)
            {
                Console.WriteLine("In catch");
            }
        }
    }

    public static void MethodTwo()
    {
        Console.WriteLine("Method Two");
        try
        {
            using (MyDisposable disposable = new MyDisposable())
            {
                throw new Exception();
            }
        }
        catch (Exception ex)
        {
            Console.WriteLine("In catch");
        }
    }

    public static void Main()
    {
        MethodOne();
        MethodTwo();
    }
}

Это напечатает:

Method One
In catch
In Dispose
Method Two
In Dispose
In catch

Ответ 7

Оператор using гарантирует, что Dispose вызывается, даже если возникает исключение, когда вы вызываете методы на объекте. Вы можете добиться того же результата, поставив объект внутри блока try и затем вызывая Dispose в блоке finally; на самом деле, это то, как оператор using транслируется компилятором.

using (Font font1 = new Font("Arial", 10.0f)) 
{
    byte charset = font1.GdiCharSet;
}

то же, что и

{
  Font font1 = new Font("Arial", 10.0f);
  try
  {
    byte charset = font1.GdiCharSet;
  }
  finally
  {
    if (font1 != null)
      ((IDisposable)font1).Dispose();
  }
}