Финализаторы необходимы, чтобы гарантировать высвобождение ограниченных ресурсов обратно в систему, таких как файловые дескрипторы, сокеты, объекты ядра и т. Д. Поскольку финализатор всегда запускается в конце срока службы объектов, это назначенное место для освобождения этих дескрипторов.
Шаблон Dispose
используется для обеспечения детерминированного уничтожения ресурсов. Поскольку сборщик мусора во время выполнения .net недетерминирован (что означает, что вы никогда не можете быть уверены, когда среда выполнения соберет старые объекты и вызовет их финализатор), был необходим метод для обеспечения детерминированного высвобождения системных ресурсов. Следовательно, если вы правильно реализуете шаблон Dispose
, вы обеспечиваете детерминированное освобождение ресурсов, а в тех случаях, когда потребитель неосторожен и не располагает объектом, финализатор очистит объект.
Простым примером необходимости Dispose
может быть быстрый и грязный метод журналирования:
public void Log(string line)
{
var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None));
sw.WriteLine(line);
// Since we don't close the stream the FileStream finalizer will do that for
// us but we don't know when that will be and until then the file is locked.
}
В приведенном выше примере файл будет заблокирован до тех пор, пока сборщик мусора не вызовет финализатор для объекта StreamWriter
. Это создает проблему, поскольку в то же время метод может вызываться снова для записи журнала, но на этот раз он не будет выполнен, поскольку файл все еще заблокирован.
Правильный способ состоит в том, чтобы располагать объект, когда закончите с его использованием:
public void Log(string line)
{
using (var sw = new StreamWriter(File.Open(
"LogFile.log", FileMode.OpenOrCreate, FileAccess.Write, FileShare.None))) {
sw.WriteLine(line);
}
// Since we use the using block (which conveniently calls Dispose() for us)
// the file well be closed at this point.
}
Кстати, технически финализаторы и деструкторы означают одно и то же; Я предпочитаю называть деструкторы c # финализаторами, так как в противном случае они имеют тенденцию путать людей с деструкторами C ++, которые в отличие от C # являются детерминированными.