Празно използване на блок

Вече беше определено тук, че празен използващ блок не е подходящ начин за отмяна 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: добре, но лично аз намирам това за нечетливо. На пръв поглед не е очевидно, че това не може да доведе до отворен ресурс. Ето защо аз също предпочитам използване (или try-catch-finally) тук. Бих използвал също using (MethodThatReturnsDisposable()){ }, тъй като изпълнението на метода може да е важно, но не искам да консумирам върнатия за еднократна употреба. - person Tim Schmelter; 25.07.2014
comment
@TimSchmelter Наистина трябва да е очевидно обаче - трябва да знаете, че File.OpenRead() връща само стойност, различна от нула. И ако знаете това, трябва също да знаете, че винаги можете безопасно да го затворите. Ако не знаете това, тогава проверявате ли неговата върната стойност за null, преди да го използвате? Защото, ако казвате, че не е очевидно, че OpenRead() не може да върне null, тогава вероятно ще пишете код, който проверява върнатата стойност за null... Както Tigran направи в неговия примерен код по-горе. - person Matthew Watson; 25.07.2014
comment
@MatthewWatson: не съм казал, че не е очевидно, че не може да бъде null, казах, че трябва да помисля малко, за да забележа, че това ще се затваря винаги и само ако няма изключение и обектът не е нулев. Вече е очевидно, да. Това, което също ми харесва при using е, че не е метод като Close, където трябва да мислите за null или не null. Намерението е ясно, извикайте метода, не правете нищо с върнатия обект, уверете се, че той винаги се изхвърля. - person Tim Schmelter; 25.07.2014

Няма много смисъл да използвате празен using блок, тъй като можете просто да добавите окончателно в края на 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