Где я могу поставить try/catch с оператором using?

Возможный дубликат:
try/catch + использование, правильный синтаксис

Я хотел бы try/catch следующее:

//write to file
using (StreamWriter sw = File.AppendText(filePath))
{
    sw.WriteLine(message);
}

Помещать ли блоки try/catch внутрь оператора using, или вокруг него, или и то, и другое?


person Ryan R    schedule 26.05.2011    source источник
comment
Вас беспокоит перехват исключений в вызовах WriteLine, AppendText и в обоих случаях?   -  person jglouie    schedule 27.05.2011
comment
Это зависит от того, сможете ли вы обработать исключение внутри используемого блока или нет, или исключение сделает весь используемый блок избыточным.   -  person PostMan    schedule 27.05.2011
comment
@jglouie Я хотел бы поймать обоих.   -  person Ryan R    schedule 27.05.2011
comment
Я не думаю, что этот вопрос должен был быть закрыт, поскольку принятый ответ на другой вопрос ужасен!   -  person Jeffrey L Whitledge    schedule 27.05.2011
comment
@Jeffrey: согласен с другим принятым ответом. Вы должны сделать репост своего сообщения под этим вопросом.   -  person Henk Holterman    schedule 27.05.2011


Ответы (3)


Если вашему оператору catch требуется доступ к переменной, объявленной в операторе using, то внутри — ваш единственный вариант.

Если вашему оператору catch нужен объект, указанный в использовании, до того, как он будет удален, тогда ваш единственный вариант — внутри.

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

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

Так что моя общая рекомендация снаружи — далеко снаружи.

private void saveButton_Click(object sender, EventArgs args)
{
    try
    {
        SaveFile(myFile); // The using statement will appear somewhere in here.
    }
    catch (IOException ex)
    {
        MessageBox.Show(ex.Message);
    }
}
person Jeffrey L Whitledge    schedule 26.05.2011
comment
+1 за «снаружи — далеко снаружи» - person hemp; 27.05.2011

Я полагаю, что это предпочтительный способ:

try
{
    using (StreamWriter sw = File.AppendText(filePath))
    {
        sw.WriteLine(message);
    }
}
catch(Exception ex)
{
   // Handle exception
}
person CD..    schedule 26.05.2011

Если вам в любом случае нужен блок try/catch, то инструкция using не принесет вам много пользы. Просто бросьте это и сделайте это вместо этого:

StreamWriter sw = null;
try
{
    sw = File.AppendText(filePath);
    sw.WriteLine(message);
}
catch(Exception)
{
}
finally
{
    if (sw != null)
        sw.Dispose();
}
person hemp    schedule 26.05.2011
comment
Очень ужасный код. Нет причин отказываться от удобства (читабельности, простоты) использования блока. - person Henk Holterman; 27.05.2011
comment
@Henk: Ты понимаешь, что это полностью субъективное мнение? Мне кажется, что блоки finally читабельны, удобны и просты. Оператор using — хороший синтаксический сахар, когда он имеет смысл, но в данном случае он не имеет смысла. - person hemp; 27.05.2011
comment
Нет, это не совсем субъективно. У вас есть около 4 дополнительных строк, связанных с «sw», и это в более широком контексте. Я думаю, что для чтения и понимания требуется примерно в 2-3 раза больше усилий. Это отстой. И есть связь с try/catch, которая предполагает отношение, которого в 99% ситуаций нет. - person Henk Holterman; 27.05.2011
comment
Согласен. Нет причин не использовать оператор using только потому, что вы хотите поймать исключение. Оператор using должен указать разработчику, а также сборщику мусора, что удаление должно произойти и своевременно! - person gcoleman0828; 17.09.2013
comment
Исправление: оператор using ничего не сообщает сборщику мусора. Он разворачивается (компилятором C#) в блок try/finally (в IL), который содержит вызов реализации метода IDisposable.Dispose() объекта. Это служит индикатором для разработчика, что удаление должно произойти, аналогично тому, как явный вызов Dispose в блоке finally указывает, что удаление должно произойти. - person hemp; 24.09.2013
comment
Хорошо... это правильно, дело было в том, что GC избавляется от него намного быстрее, независимо от того, как это происходит. Приведенный выше код менее элегантен и более подвержен ошибкам из-за забывания оператора finally, как это делают многие разработчики. Из MSDN Оператор using гарантирует, что Dispose вызывается, даже если во время вызова методов объекта возникает исключение. - person gcoleman0828; 26.09.2013
comment
Вероятность того, что вы забудете вызвать dispose в блоке finally, не выше, чем вероятность того, что вы забудете обернуть объект в блок using (как это делают многие разработчики). Из MSDN. Блок finally полезен для очистки любых ресурсов... Я думаю, что мы полностью забили этот блок до смерти. - person hemp; 26.09.2013
comment
@hemp в значительной степени прав во всем этом дискурсе. Хотя я бы по-прежнему поощрял using даже внутри try/catch просто ради согласованности, если программисты не знают, что они должны избавляться от объекта, то ни один из шаблонов не будет иметь значения. Это касается исключительно предпочтений, которые по определению субъективны. Мне нравится идея поместить его здесь в блок finally, но я не буду просто потому, что боюсь запутать других программистов, которые могут не понять. - person crush; 24.11.2014
comment
Из соглашений о кодировании MSDN: если у вас есть оператор try-finally, в котором единственным кодом в блоке finally является вызов метода Dispose, вместо этого используйте оператор using. - person Bugalugs Nash; 10.07.2015
comment
Конечно. Однако оператор try-finally отличается от оператора try-catch-finally. - person hemp; 22.07.2015
comment
@hemp Рад, что нашел ваши аргументы! - person chadiik; 26.02.2017