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'. Вследствие этого ресурсы будут освобождаться уже после выполнения действий над потоком. Следовательно, исключение выброшено не будет.
Данная диагностика классифицируется как: