C # с помощью оператора ловить ошибку - PullRequest
28 голосов
/ 30 октября 2008

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

 using (SqlCommand cmd = 
     new SqlCommand(reportDataSource, 
         new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString)))
 {
     cmd.CommandType = CommandType.StoredProcedure;
     cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year;
     cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start;
     cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end;
     cmd.Connection.Open();

     DataSet dset = new DataSet();
     new SqlDataAdapter(cmd).Fill(dset);
     this.gridDataSource.DataSource = dset.Tables[0];
 }

Кажется, это работает, но есть ли смысл в этом, поскольку, насколько я могу судить, мне все еще нужно заключить это в блок try catch, чтобы перехватить непредвиденные ошибки, например. Сервер SQL вниз. Я что-то упустил?

Насколько я сейчас вижу, это просто останавливает меня, когда я закрываю и удаляю cmd, но будет еще больше строк кода из-за необходимости ловить попытку.

Ответы [ 16 ]

1 голос
/ 30 октября 2008

FYI, в этом конкретном примере, поскольку вы используете соединение ADO.net и объект Command, имейте в виду, что оператор using просто выполняет Command.Dispose и Connection.Dispose (), которые фактически не закрывают соединение, но просто высвобождает его обратно в пул соединений ADO.net для повторного использования в следующем файле connection.open ... что хорошо, и абсолютно правильно, bc, если вы этого не сделаете, соединение останется неиспользуемым до тех пор, пока сборщик мусора не выпустит его обратно в пул, что может произойти только после многочисленных других запросов на подключение, которые в противном случае были бы вынуждены создавать новые подключения, даже если есть неиспользуемый, ожидающий сбора мусора.

1 голос
/ 30 октября 2008

Оператор using фактически заменен компилятором на блок try / finally, в котором параметр параметра using утилизируется до тех пор, пока он реализует интерфейс IDisposable. Кроме того, что указанные объекты должным образом удаляются, когда они выпадают из области видимости, при использовании этой конструкции на самом деле не происходит захват ошибок.

Как указано TheSoftwareJedi выше, вы должны убедиться, что объекты SqlConnection и SqlCommand утилизированы должным образом. Объединение обоих в один блок с использованием немного беспорядочно и может не сработать так, как вы думаете.

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

0 голосов
/ 27 июня 2015

Во-первых, ваш пример кода должен быть:

using (SqlConnection conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, conn))
{
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year;
    cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start;
    cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end;
    cmd.Connection.Open();

    DataSet dset = new DataSet();
    new SqlDataAdapter(cmd).Fill(dset);
    this.gridDataSource.DataSource = dset.Tables[0];
}

С кодом в вашем вопросе исключение, создающее команду, приведет к тому, что только что созданное соединение не будет удалено. С учетом вышеизложенного, соединение правильно расположено.

Если вам нужно обработать исключения в конструкции соединения и команды (а также при их использовании), да, вы должны обернуть все это в try / catch:

try
{
    using (SqlConnection conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
    using (SqlCommand cmd = new SqlCommand(reportDataSource, conn))
    {
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year;
        cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start;
        cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end;
        cmd.Connection.Open();

        DataSet dset = new DataSet();
        new SqlDataAdapter(cmd).Fill(dset);
        this.gridDataSource.DataSource = dset.Tables[0];
    }
}
catch (RelevantException ex)
{
    // ...handling...
}

Но вам не нужно заниматься уборкой conn или cmd; это уже сделано для вас.

Контраст с тем же самым без using:

SqlConnection conn = null;
SqlCommand cmd = null;
try
{
    conn = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString);
    cmd = new SqlCommand(reportDataSource, conn);
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year;
    cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start;
    cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end;
    cmd.Connection.Open();

    DataSet dset = new DataSet();
    new SqlDataAdapter(cmd).Fill(dset);
    this.gridDataSource.DataSource = dset.Tables[0];
}
catch (RelevantException ex)
{
    // ...handling...
}
finally
{
    if (cmd != null)
    {
        try
        {
            cmd.Dispose();
        }
        catch { }
        cmd = null;
    }
    if (conn != null)
    {
        try
        {
            conn.Dispose();
        }
        catch { }
        conn = null;
    }
}
// And note that `cmd` and `conn` are still in scope here, even though they're useless

Я знаю, что лучше написать. : -)

0 голосов
/ 12 августа 2010

Незначительная поправка к примеру: SqlDataAdapter также необходимо создать в выражении using:

using (SqlConnection con = new SqlConnection(Settings.Default.qlsdat_extensionsConnectionString))
using (SqlCommand cmd = new SqlCommand(reportDataSource, con))
{
    cmd.CommandType = CommandType.StoredProcedure;
    cmd.Parameters.Add("@Year", SqlDbType.Char, 4).Value = year;
    cmd.Parameters.Add("@startDate", SqlDbType.DateTime).Value = start;
    cmd.Parameters.Add("@endDate", SqlDbType.DateTime).Value = end;
    con.Open();

    DataSet dset = new DataSet();
    using (SqlDataAdapter adapter = new SqlDataAdapter(cmd))
    {
        adapter.Fill(dset);
    }
    this.gridDataSource.DataSource = dset.Tables[0];
}
0 голосов
/ 25 марта 2010

Таким образом, «использование» в точности совпадает с «Try / catch / finally», только намного более гибко для обработки ошибок.

0 голосов
/ 30 октября 2008

Если вызывающая сторона вашей функции отвечает за работу с любыми исключениями, оператор using - это хороший способ обеспечить очистку ресурсов независимо от результата.

Позволяет размещать код обработки исключений на границах слоев / сборок и помогает предотвратить перегруженность других функций.

Конечно, это действительно зависит от типов исключений, генерируемых вашим кодом. Иногда вы должны использовать try-catch-finally, а не оператор using. Моя привычка - всегда начинать с оператора using для IDisposables (или иметь классы, содержащие IDisposables, также реализующие интерфейс) и добавлять try-catch-finally при необходимости.

...