Требуется ли Try / Catch / finally с помощью оператора Using для обработки исключений? - PullRequest
3 голосов
/ 31 января 2012

Интересно, как использовать операторы, обрабатывающие исключения?Нужно ли обернуть оператор using выражением Try / Cath / finally , чтобы быть уверенным, что объект SqlConnection закрыт и удаляется, даже если содержащий код выдает исключение?

Public Function GetUserAccountKeyByUsername(ByVal pUsername As String) As Int32
    If String.IsNullOrEmpty(pUsername) Then
        Throw New ArgumentNullException("pUsername", "Username is missing")
    End If

    Dim o As Object
    Dim userAccountKey As Int32
    Dim SQL As StringBuilder = New StringBuilder()

    With SQL
        .Append("SELECT USER_KEY ")
        .Append("FROM USER ")
        .Append("WHERE USERNAME = @Username ")
    End With

    Try
        Using conn As SqlConnection = New SqlConnection(ConnectionString)
            conn.Open()
            Using cmd As SqlCommand = New SqlCommand(SQL.ToString, conn)
                Try
                    cmd.CommandTimeout = Convert.ToInt32(ConfigurationManager.AppSettings("SQLQueryLimitTime"))
                    cmd.Parameters.Add(New SqlParameter("@Username", SqlDbType.VarChar)).Value = pUsername
                    o = cmd.ExecuteScalar()
                    If (o IsNot Nothing) AndAlso Not (IsDBNull(o)) Then
                        userAccountKey = Convert.ToInt32(o)
                    End If
                Catch ex As Exception
                    _log.logError(ex, cmd)
                End Try
            End Using
        End Using
    Catch ex As Exception
        _log.logError(ex, conn.ConnectionString)
    Finally
        conn.Close()
        conn.Dispose()
    End Try
    Return userAccountKey
End Function

Ответы [ 3 ]

10 голосов
/ 31 января 2012

using помещает try и finally в ваш код и автоматически вызывает .Dispose(), и в конечном итоге .Close() coz DbConnection.Dispose() вызывает Close(), но здесь нет подвоха, поэтому вам нужно будет добавить catch над using блоком, что-то вроде этого

try
{
   using(some resource)
   {
   }
}
catch(Exception)
{
}

против

try
{
}
catch(Exception)
{
}
finally{ }

Итак, глядя на это, вы можете подумать, что Try / Catch / Наконец лучше, чем Использование , потому что в using в любом случае вам нужно обработать ошибку, , но это не .

Если во время .Close() или .Dispose() возникнет какая-либо ошибка, первый образец тоже с этим справится, но во втором случае вам придется поместить try-catch в блок finally.

Подробнее о Избегание проблем с помощью оператора Using (MSDN)

Надеюсь, это ответит на ваш вопрос.

3 голосов
/ 31 января 2012

Вам не нужно записывать его заново, его автоматически создают в соответствии с кодом ..

Ответ на C #, но в VB.NET все работает так же

Использование блока в C # очень удобно при работе с одноразовыми предметами. Одноразовые объекты - это те объекты, которые могут явно освобождать ресурсы, которые они используют при вызове для удаления. Как мы знаем, сборка мусора в .Net недетерминирована, поэтому вы не можете предсказать, когда именно объект будет собирать мусор.

Прочтите этот пост более подробно: понимание блока с использованием в C #

Код файла CS

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace BlogSamples
{
    class Program
    {
        static void Main(string[] args)
        {
            using (Car myCar = new Car(1))
            {
                myCar.Run();
            }
        }
    }
}

код MSIL

.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       37 (0x25)
  .maxstack  2
  .locals init ([0] class BlogSamples.Car myCar,
           [1] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  newobj     instance void BlogSamples.Car::.ctor(int32)
  IL_0007:  stloc.0
  .try
  {
    IL_0008:  nop
    IL_0009:  ldloc.0
    IL_000a:  callvirt   instance void BlogSamples.Car::Run()
    IL_000f:  nop
    IL_0010:  nop
    IL_0011:  leave.s    IL_0023
  }  // end .try
  finally
  {
    IL_0013:  ldloc.0
    IL_0014:  ldnull
    IL_0015:  ceq
    IL_0017:  stloc.1
    IL_0018:  ldloc.1
    IL_0019:  brtrue.s   IL_0022
    IL_001b:  ldloc.0
    IL_001c:  callvirt   instance void [mscorlib]System.IDisposable::Dispose()
    IL_0021:  nop
    IL_0022:  endfinally
  }  // end handler
  IL_0023:  nop
  IL_0024:  ret
} // end of method Program::Main
2 голосов
/ 31 января 2012

Да, вам нужен блок try catch, например, для регистрации исключения, как показано в вашем коде.Блок using обеспечивает вызов Dispose, но не обрабатывает исключения.

...