# V3114. IDisposable object is not disposed before method returns.

Чтобы понять смысл данной диагностики, давайте для начала немного вспомним теорию.

Сборщик мусора автоматически освобождает память, связанную с контролируемым объектом, если он больше не используется и на него не осталось видимых ссылок. Тем не менее, невозможно предсказать, когда именно произойдёт сборка мусора (если не вызывать её вручную). Кроме того, сборщик мусора не имеет информации о таких неуправляемых ресурсах, как дескрипторы, окна или открытые файлы и потоки. Метод 'Dispose' обычно используется, чтобы освобождать такие неуправляемые ресурсы.

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

Если предположить, что данный объект содержит какой-либо дескриптор (например, файл), то он будет оставаться в памяти до следующей сборки мусора, которая произойдет через неопределенный промежуток времени вплоть до момента завершения работы программы. В результате файл может неопределённое время оставаться заблокированным, мешая нормальной работе других программ или операционной системе.

Рассмотрим пример такой ситуации:

    string Foo()
    {
      var stream = new StreamReader(@"С:\temp.txt");
      return stream.ReadToEnd();
    }

В данном случае объект 'StreamReader' будет хранить в себе дескриптор открытого файла даже после выхода из метода 'Foo', тем самым блокируя его для других программ и операционной системы до тех пор, пока сборщик мусора не очистит его.

Чтобы избежать этого - своевременно освобождайте ресурсы, используя метод 'Dispose' как в примере ниже:

    string Foo()
    {
      var stream = new StreamReader(@"С:\temp.txt");
      var result = stream.ReadToEnd();

      stream.Dispose();
      return result;
    }

Однако, для более надёжного освобождения ресурсов рекомендуется использовать конструкцию 'using'. Она обеспечит автоматическую очистку ресурсов используемого объекта после завершения:

    string Foo()
    {
      using (var stream = new StreamReader(@"С:\temp.txt"))
      {
        return stream.ReadToEnd();
      }
    }

Компилятор раскроет блок 'using' в блок 'try finally', и в 'finally' вставит вызов метода 'Dispose' - это гарантирует очистку объекта даже в случае возникновения исключений.

Выявляемые диагностикой ошибки классифицируются согласно ГОСТ Р 71207–2024 как критические и относятся к типу: Ошибки утечек памяти, незакрытых файловых дескрипторов и дескрипторов сетевых соединений [* см. примечание касательно языков C#, Java].

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

CWE-404

Взгляните на примеры ошибок, обнаруженных с помощью диагностики V3114.