Очистить с помощью блока

Уже было определено здесь, что пустой блок использования не является подходящим способом переопределения Dispose(), а как насчет следующего случая?

Является ли это законным использованием пустого блока using?

try
{
    using (File.OpenRead(sourceFile)) { }
}
catch (FileNotFoundException)
{
    error = "File not found: " + sourceFile;
}
catch (UnauthorizedAccessException)
{
    error = "Not authorized to access file: " + sourceFile;
}
catch (Exception e)
{
    error = "Error while attempting to read file: " + sourceFile + ".\n\n" + e.Message;
}

if (error != null)
    return error;

System.Diagnostics.Process.Start(sourceFile);

person Dan Bechard    schedule 25.07.2014    source источник
comment
Вы просто проверяете, можете ли вы получить доступ и прочитать файл, вам на самом деле не нужно содержимое?   -  person Michael McGriff    schedule 25.07.2014
comment
Поскольку using в основном расширяется до try { ... } finally { ... }, ваши действия приведут к чему-то вроде try { try { ...} finally { ... } } catch ( ... ) { ... } catch ( ... ) { ... } catch ( ... ) { ... }.   -  person Corak    schedule 25.07.2014
comment
@MichaelMcGriff Я исключил это для простоты. Отредактировано, чтобы предоставить немного больше контекста, но это не имеет отношения к обсуждению.   -  person Dan Bechard    schedule 25.07.2014
comment
Контекст @Dan почти всегда актуален :) Почему бы вам просто не попробовать запустить процесс и отловить там любые исключения?   -  person Michael McGriff    schedule 25.07.2014
comment
@MichaelMcGriff Process.Start не генерирует те же исключения, что и OpenRead, поэтому сложнее определить, что пошло не так.   -  person Dan Bechard    schedule 25.07.2014
comment
Я был бы в порядке с этим, если бы у вас был комментарий. В противном случае вы можете использовать этот шаблон   -  person Conrad Frix    schedule 25.07.2014
comment
@ConradFrix Существует множество других исключений, помимо IOException, которые могут быть выброшены.   -  person Dan Bechard    schedule 25.07.2014
comment
@ Дэн. Да, так что вам придется добавить их. Дело в том, что использование блока finally может убрать часть запаха using внутри блока try.   -  person Conrad Frix    schedule 25.07.2014


Ответы (2)


Нет, это неправомерное использование пустого блока использования.

Вы можете просто написать попытку следующим образом:

try
{
    File.OpenRead(sourceFile).Close();
}

Либо OpenRead() завершится успешно и вернет поток, который вы должны закрыть (или удалить, но я думаю, что .Close() лучше выражает ваше намерение), либо выдаст исключение и ничего не вернет.

Поэтому вы всегда можете просто закрыть возвращаемое значение.

(Я предполагаю, что вы просто проверяете доступ для чтения, прежде чем делать что-то еще. Однако имейте в виду, что теоретически у вас может быть состояние гонки, потому что доступность файла может измениться между выполнением этой проверки и последующим открытием файла. На практике это маловероятно, но вы должны знать о такой возможности.)

person Matthew Watson    schedule 25.07.2014
comment
Но если OpenRead бросает, то не закрывается. - person Tim Schmelter; 25.07.2014
comment
@TimSchmelter Если OpenRead бросает, он не открывается, поэтому закрывать нечего. - person Dan Bechard; 25.07.2014
comment
@TimSchmelter Если выдает OpenRead(), файл не открывается и ничего не возвращает. - person Matthew Watson; 25.07.2014
comment
@MatthewWatson: а, хорошо, но лично я нахожу это нечитаемым. На первый взгляд не очевидно, что это не может привести к открытому ресурсу. Вот почему я также предпочитаю использование (или попытку поймать-наконец) здесь. Я бы также использовал using (MethodThatReturnsDisposable()){ }, потому что выполнение метода может быть важным, но я не хочу использовать возвращенный одноразовый. - person Tim Schmelter; 25.07.2014
comment
@TimSchmelter Это действительно должно быть очевидно - вы должны знать, что File.OpenRead() всегда возвращает ненулевое значение. И если вы это знаете, вы также должны знать, что вы всегда можете безопасно закрыть его. Если вы этого не знаете, то проверяете ли вы возвращаемое значение на null перед его использованием? Потому что, если вы говорите, что не очевидно, что OpenRead() не может возвращать null, то вы, по-видимому, пишете код, который проверяет возвращаемое значение на null... Как это сделал Тигран в своем примере кода выше. - person Matthew Watson; 25.07.2014
comment
@MatthewWatson: я не сказал, что не очевидно, что это не может быть null, я сказал, что должен подумать, чтобы заметить, что это будет закрываться всегда и только в том случае, если нет исключения и объект не является нулевым. Теперь это очевидно, да. Что мне также нравится в using, так это то, что это не такой метод, как Close, где вам нужно думать о нулевом или не нулевом значении. Цель ясна, вызовите метод, ничего не делайте с возвращенным объектом, убедитесь, что он всегда удаляется. - person Tim Schmelter; 25.07.2014

Нет особого смысла использовать пустой блок using, так как вы можете просто добавить finally в конец цепочек catch и обработать Dispose там:

FileStream fs;
try {

    fs = File.OpenRead(sourceFile); 
}
catch(..) {
}
catch(..) {
}
catch(..) {
}
finally {

  if(fs !=null) {
      fs.Close();
      fs.Dispose();

  }
}
person Tigran    schedule 25.07.2014
comment
Это по-прежнему кажется невероятно бессмысленным, поскольку все, что он пытается сделать, это увидеть, существует ли файл и есть ли у него доступ к нему. Нехорошее использование OpenRead. - person Dave Zych; 25.07.2014
comment
@DaveZych: кажется, это не только для проверки наличия файла. но более того, в этом случае вы также можете получить обратную связь о причине проблемы. - person Tigran; 25.07.2014
comment
@DaveZych Он проверяет любые ошибки, которые мешают пользователю прочитать файл, а не только File.Exists(). - person Dan Bechard; 25.07.2014
comment
Обратите внимание, что этот код на самом деле не скомпилируется, если вы не инициализируете fs значением null. - person Matthew Watson; 25.07.2014
comment
@MatthewWatson: да, вы также не можете использовать catch(..). это просто псевдокод, чтобы дать представление. - person Tigran; 25.07.2014