Правильная утилизация файловых потоков и двоичных потоков и утилизация файловых потоков - PullRequest
3 голосов
/ 01 января 2012

На самом деле, я попытался защитить свой код от ошибок и в итоге он выглядел довольно грязно.

У меня есть функция, настроенная для чтения файлов определенного типа.Я хочу, чтобы функция возвращала false, если возникла проблема, или true, если все работало.У меня проблемы с выяснением, как все структурировать.

У меня есть начальный блок try-catch, который пытается открыть поток файлов.После этого у меня есть некоторые другие проверки, которые я делаю в процессе чтения, такие как размер файла и значения при определенных смещениях.Я настроил это с помощью операторов if else.Например:

if(condition){

}
else{
    MessageBox.Show("There was an error");
    br.Dispose();
    fs.Dispose();
    return false;
}

... br - двоичный читатель и fs файловый поток.Подобных блоков много, и кажется плохой практикой писать одно и то же много раз.Первое, что приходит на ум, - это обернуть все это в оператор try-catch и генерировать исключения вместо использования блоков if else.Я помню, когда читал об операторах try-catch, что хорошо иметь их, но не оборачивать ими все.Честно говоря, я до сих пор не до конца понимаю, почему было бы плохой практикой оборачивать все в операторы try catch, поскольку они дают эффект только при наличии ошибки, и в этом случае программа все равно идет на юг ...

Кроме того, мне нужно закрыть двоичный считыватель и поток файлов или закроет один из них, закрыв другой?Есть ли способ использовать их, не избавляясь от них?

Ответы [ 5 ]

5 голосов
/ 01 января 2012

Как насчет использования ключевого слова using? это оборачивает ваше использование IDisposable в блоке try - finally;

bool success = true;

using(var fs = new FileStream(fileName, FileMode.Create)))
using(var br = new BinaryReader(fs))
{
  // do something
  success = result;
}

return success;

Вложенные блоки использования гарантируют, что как файловый поток, так и двоичный читатель всегда правильно закрыты и расположены.

Вы можете прочитать подробнее об использовании в MSDN . Это делает использование IDisposable немного более аккуратным, устраняя необходимость явной обработки исключений.

Относительно вашего заявления:

Я помню, когда читал об операторах try-catch, что это хорошо для иметь их, но не оборачивать ими все.

Я всегда использую простое правило, что, если я не могу обработать и восстановить исключение в определенном блоке кода, не пытайтесь его перехватить. Разрешить исключению «накапливать» стек до точки, где имеет смысл его перехватить. При таком подходе вы обнаружите, что вам не нужно добавлять много блоков try-catch, вы будете склонны использовать их в точке интеграции со службами (такими как файловая система, сеть и т. Д.), Но ваша бизнес-логика почти всегда без механизмов обработки исключений.

1 голос
/ 01 января 2012

Просто используйте ключевое слово using для ваших одноразовых предметов.В блоке ключевого слова using вы можете throw исключения или return, не беспокоясь об утилизации;это произойдет автоматически для вас. Блоки

try-catch не очень хорошая идея только потому, что существует гораздо лучшая альтернатива: блоки try-finally.Но ключевое слово using даже лучше, потому что оно по существу расширяется в блок try-finally и заботится об удалении объектов.

Закрытие потока файлов также закроет двоичное считывающее устройство, как и удаление ихделать.Почему вы хотите использовать их без утилизации?Утилизация их лучше, а удаление через using - лучшее, что можно сделать.

0 голосов
/ 01 января 2012

Используйте ключевое слово using.С помощью using вы можете переписать что-то вроде этого:

public static int CountCars()
{
    SqlConnection conn = new SqlConnection(connectionString);
    try
    {
      SqlCommand cmd = conn.CreateCommand();
      conn.Open();
      try
      {
        cmd.CommandText = "SELECT COUNT(1) FROM Carsd";

        return (int)cmd.ExecuteScalar();
      }
      finally
      {
        if(cmd != null)
          cmd.Dispose();
      }
    }
    finally
    {
      if(cmd != null)
        conn.Dispose();
    }
}

в это:

public static int CountCars()
{
    using(SqlConnection conn = new SqlConnection(connectionString))
    using(SqlCommand cmd = conn.CreateCommand())
    {
        conn.Open();
        cmd.CommandText = "SELECT COUNT(1) FROM Carsd";

        return (int)cmd.ExecuteScalar();
    }

}

Оба фрагмента кода при компиляции будут давать точно такой же код IL.Примеры взяты из http://coding.abel.nu/2011/12/idisposable-and-using-in-c/, где я написал более подробную информацию об использовании и IDisposable.

0 голосов
/ 01 января 2012

Да, это плохая практика.

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

if (headNotValid)
   throw new Exception("Header was not valid");

В некоторых случаях рекомендуется создать новый класс исключений.

При работе с классами, которые наследуются от IDisposable, следует использовать директиву using.

using (var stream = new FileStream(filename))
{
}

Это гарантирует, что ваш поток будет удален, даже если в блоке using выброшено исключение.

В целом, я бы предпочел что-то вроде этого:

private void string ParseFile(string filename)
{
     using (var stream = new FileStream(filename))
     {
           if (somethingNotValid)
              throw new Exception(...);

           return ...;
     }
}

А в твоем основном:

{
     try
     {
          var value = ParseFile(filename);
     }
     catch (Exception)
     {
          Console.WriteLine(..);
     }
}
0 голосов
/ 01 января 2012

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

using (FileStream)
{
    ....
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...