>
>
>
V3178. Calling method or accessing prop…


V3178. Calling method or accessing property of potentially disposed object may result in exception.

Анализатор обнаружил вызов метода или обращение к свойству объекта, у которого ранее был вызван метод 'Dispose' или его аналог. Подобные действия могут привести к выбрасыванию исключения.

Рассмотрим пример:

public void AppendFileInformation(string path)
{
  FileStream stream = new FileStream(path,
                                     FileMode.Open,
                                     FileAccess.Read);
  ....
  stream.Close();
  ....
  if (stream.Length == stream.Position)
  {
    Console.WriteLine("End of file has been reached.");
    ....
  }
  ....
}

В условии проверяется, что файл был прочитан полностью. Для проверки сравнивают текущую позицию потока и его длину. Проблема в том, что при обращении к свойству 'Length' будет выброшено исключение типа 'ObjectDisposedException'. Это связано с тем, что перед условием у переменной 'stream' вызывается метод 'Close'. Для класса 'FileStream' этот метод является аналогом 'Dispose'. Следовательно, ресурсы 'stream' будут освобождены.

Рассмотрим корректную реализацию 'AppendFileInformation':

public void AppendFileInformation(string path)
{
  using (FileStream stream = new FileStream(path,
                                            FileMode.Open,
                                            FileAccess.Read))
  {
    ....
    if (stream.Length == stream.Position)
    {
      Console.WriteLine("End of file has been reached.");
    }
    ....
  }
  ....
}

Для корректной работы метода стоит использовать выражение 'using'. В этом случае:

  • ресурсы объекта 'stream' будут автоматически освобождены после выхода из тела 'using';
  • вне тела 'using' обратиться к объекту не получится – это даёт дополнительную защиту от исключений типа 'ObjectDisposedException';
  • даже если в теле 'using' возникнет исключение, ресурсы всё равно будут освобождены.

Ещё один вариант ошибки выглядит следующим образом:

public void ProcessFileStream(FileStream stream)
{
  ....
  bool flag = CheckAndCloseStream(stream);
  AppendFileInformation(stream);
  ....
}

public bool CheckAndCloseStream(FileStream potentiallyInvalidStream)
{
  ....
  potentiallyInvalidStream.Close();
  ....
}

public void AppendFileInformation(FileStream streamForInformation)
{
  ....
  if (streamForInformation.Length == streamForInformation.Position)
  {
    Console.WriteLine("End of file has been reached.");
  }
  ....
}

После вызова 'CheckAndCloseStream' в методе 'ProcessFileStream' ресурсы объекта, на который ссылается переменная 'stream', будут освобождены. Далее эта переменная передаётся в метод 'AppendFileInformation'. Внутри него производится обращение к свойству 'Length', из-за чего будет выброшено исключение типа 'ObjectDisposedException'.

Корректная реализация 'ProcessFileStream' будет выглядеть следующим образом:

public void ProcessFileStream(FileStream stream)
{
  ....
  AppendFileInformation(stream);
  bool flag = CheckAndCloseStream(stream);
  ....
}

Был изменён порядок вызовов методов 'CheckAndCloseStream' и 'AppendFileInformation'. Вследствие этого ресурсы будут освобождаться уже после выполнения действий над потоком. Следовательно, исключение выброшено не будет.

Данная диагностика классифицируется как: