Писать собственный деструктор (он же финализатор) неправильно в 99,99% случаев. Они необходимы для того, чтобы ваш класс высвобождал ресурс операционной системы, который не управляется автоматически .NET Framework и не был должным образом выпущен пользователем вашего класса.
Это начинается с того, что сначала нужно выделить ресурс операционной системы в своем собственном коде. Это всегда требует какой-то P / Invoke. Это очень редко требуется, это была работа программистов .NET, работающих в Microsoft, чтобы позаботиться об этом.
Они сделали в случае StreamWriter. Через несколько слоев это оболочка вокруг дескриптора файла, созданная с помощью CreateFile (). Класс, создавший дескриптор, также отвечает за написание финализатора. Код Microsoft, а не ваш.
Такой класс всегда реализует IDisposable, предоставляя пользователю класса возможность освободить ресурс, когда он будет сделан с ним, вместо того, чтобы ждать, пока финализатор выполнит свою работу. StreamWriter реализует IDisposable.
Конечно, ваш объект StreamWriter является частной реализацией вашего класса. Вы не знаете, когда пользователь завершил работу с вашим классом Logger, вы не можете автоматически вызывать StreamWriter.Dispose (). Тебе нужна помощь.
Получите эту помощь, внедрив IDisposable самостоятельно. Пользователь вашего класса теперь может вызывать Dispose или использовать оператор using, как он это делает с любым из классов каркаса:
class Logger : IDisposable {
private StreamWriter sw;
public void Dispose() {
sw.Dispose(); // Or sw.Close(), same thing
}
// etc...
}
Ну, это то, что вы должны делать в 99,9% всех случаев. Но не здесь. Риск путаницы с вашей стороны: если вы реализуете IDisposable, у пользователя вашего класса также должна быть разумная возможность вызвать его метод Dispose (). Это обычно не большая проблема, за исключением класса типа Logger. Весьма вероятно, что ваш пользователь захочет записать что-нибудь до самого последнего момента. Так что она может записать необработанное исключение из AppDomain.UnhandledException, например.
Когда вызывать Dispose () в этом случае? Вы можете сделать это, когда ваша программа заканчивается. Но это, помимо того, что нет особого смысла в раннем освобождении ресурсов, если это происходит при выходе из программы.
Регистратор предъявляет особые требования к надлежащему отключению во всех случаях. Для этого необходимо установить для свойства StreamWriter.AutoFlush значение true, чтобы выходные данные журнала сбрасывались сразу после записи. Учитывая сложность правильного вызова Dispose (), теперь на самом деле лучше не реализовывать IDisposable и позволить финализатору Microsoft закрыть дескриптор файла.
Fwiw, есть другой класс в рамках, который имеет ту же проблему. Класс Thread использует четыре дескриптора операционной системы, но не реализует IDisposable. Вызов Thread.Dispose () действительно действительно неудобен, поэтому Microsoft не реализовала его. Это вызывает проблемы в очень необычных случаях, вам нужно написать программу, которая создает много потоков, но никогда не использует оператор new для создания объектов класса. Это было сделано.
Последнее, но не менее важное: написание логгера довольно сложно, как объяснено выше. Log4net является популярным решением. NLog - лучшая мышеловка, библиотека, которая чувствует и работает dotnetty вместо ощущения как порт Java.