Почему "использование" не имеет блока catch?

Я понимаю, что точка "использования" заключается в том, чтобы гарантировать, что будет вызываться метод Dispose объекта. Но как должно обрабатываться исключение в инструкции "using" ? Если есть исключение, мне нужно обернуть мой оператор "using" в try catch. Например:


Допустим, что существует исключение, созданное при создании объекта внутри параметра использования

 try
 {
    // Exception in using parameter
    using (SqlConnection connection = new SqlConnection("LippertTheLeopard"))
    {
       connection.Open();
    }
 }
 catch (Exception ex)
 {

 }

Или Исключение в области использования

 using (SqlConnection connection = new SqlConnection())
 {
    try
    {
       connection.Open();
    }
    catch (Exception ex)
    {

    }
 }

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

 SqlConnection connection2 = null;
 try
 {
    connection2 = new SqlConnection("z");
    connection2.Open();
 }
 catch (Exception ex)
 {

 }
 finally
 {
    IDisposable disp = connection2 as IDisposable;
    if (disp != null)
    {
       disp.Dispose();
    }
 }

Может ли синтаксис синтаксиса "using" быть немного более сладким...
Конечно, было бы неплохо иметь это:

 using (SqlConnection connection = new SqlConnection())
 {
    connection.Open();
 }
 catch(Exception ex)
 {
   // What went wrong? Well at least connection is Disposed
 }

Ответ 1

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

Вместо этого мне нужно разрешить ему перейти на следующий уровень — обрабатывайте его в функции, которая называется этот код, а не там.

Ответ 2

Потому что вы будете "скрывать" дополнительные функции внутри ключевого слова, не связанного с ним.

Однако вы всегда можете написать это так

using (...) try
{
}
catch (...)
{
}

И таким образом строка представляет ваши намерения - оператор using, который также является попыткой

Ответ 3

using Не имеет никакого отношения к обработке ошибок. Это сокращает "call Dispose, когда вы покидаете этот блок". Ваш второй пример кода вполне приемлем... почему беспорядок с тем, что работает?

Ответ 4

Блок использования - это просто синтаксический сахар для блока try-finally. Если вам нужно предложение catch, просто используйте try-catch-finally:

SqlConnection connection;
try 
{
    connection = new SqlConnection();
    connection.Open();
}
catch(Exception ex)
{
    // handle
}
finally 
{
    if (connection != null)
    {
        connection.Dispose();
    }
}

Да, это больше кода, чем ваш теоретический "использование-catch"; Я сужу, что разработчики языка не считали это очень высоким приоритетом, и я не могу сказать, что когда-либо ощущал его потерю.

Ответ 5

Интересная идея, но это создало бы следующую путаницу:

 using (SqlConnection connection = new SqlConnection())
 using (SqlCommand cmd = new SqlCommand())
 {
     connection.Open();
 }
 catch(Exception ex)
 {
     // Is connection valid? Is cmd valid?  how would you tell?
     // if the ctor of either throw do I get here?
 }

Ответ 6

На мой взгляд, вы смешиваете проблемы. Управление ресурсами (т.е. Удаление объектов) полностью отделено от обработки исключений. Индивидуальное сопоставление, которое вы описываете в своем вопросе, является просто особым случаем. Обычно обработка исключений не будет происходить в том же месте, где заканчивается область использования. Или вы можете иметь несколько областей try-catch внутри используемого блока. Или...

Ответ 7

Я рекомендую вам использовать пример # 1 и # 2 вместе. Причина в том, что ваш оператор использования может, например, прочитать файл и выбросить исключение (например, файл не найден). Если вы его не поймаете, у вас есть необработанное исключение. Помещение блока catch try внутри используемого блока будет только улавливать исключения, которые возникают после выполнения инструкции using. Комбинация вашего примера одна и вторая лучше всего ИМХО.

Ответ 8

Цель оператора "Использовать" состоит в том, чтобы гарантировать, что будет выполняться какой-либо тип операции очистки, когда выполнение завершает блок кода, независимо от того, проходит ли этот выход через провал, исключение или return. Когда блок выйдет через любое из этих средств, он вызовет Dispose по параметру using. Блок существует, в некотором смысле, в интересах того, что указывается как параметр using, и вообще, что все равно, почему этот блок был удален.

Есть несколько необычных случаев, для которых положения могут быть полезными; их уровень дополнительной полезности будет значительно ниже, чем при условии using в первую очередь (хотя, возможно, лучше, чем некоторые другие функции, которые разработчики считают нужным):

(1) Существует очень распространенный шаблон в конструкторах или фабриках объектов, которые инкапсулируют другие объекты IDisposable; если конструктор или factory выходит из исключения, инкапсулированные объекты должны быть Dispose d, но если он выходит через return, они не должны. В настоящее время такое поведение должно быть реализовано с помощью try/catch или путем объединения try/finally с флагом, но это было бы полезно, если бы существовал либо вариант using, который вызывал бы только вызов Dispose, когда он вышел из-за исключения, или же оператор keep using, который исключает временное использование оператором using для хранения объекта, который требует удаления (поскольку using не может предшествовать идентификатор, такой функция может быть добавлена ​​способом, несколько аналогичным yield return).

(2) В некоторых случаях было бы полезно, если ключевое слово finally было расширено для принятия аргумента Exception; он будет содержать исключение, из-за которого защищенное предложение выйдет (если есть) или null, если охраняемое предложение выходит из строя (через возврат или провал), и если блок using может использовать interface IDisposeExOnly {void DisposeEx(Exception ex);} и Interface IDisposeEx : IDisposable, IDisposableExOnly {} (во время компиляции, выбранных DisposeEx(), если они реализованы, или Dispose() в противном случае). Это может позволить объектам на основе транзакций безопасно поддерживать автоматическую фиксацию (т.е. Выполнить фиксацию, если исключение прошедшего отказа null или возврат назад, если не нуль), а также позволит улучшить регистрацию в ситуациях, когда Dispose не удается как следствие проблемы в защищенном предложении (правильная вещь для Dispose должна генерировать исключение, которое инкапсулирует как исключение, которое было ожидающим, когда оно было вызвано, так и исключение, которое произошло как следствие, но там в настоящее время нет чистого способа сделать это).

Я не знаю, добавит ли Microsoft такие функции; первая и первая часть второй, будут полностью обрабатываться на уровне языка. Последняя часть второй будет на уровне Framework.