Ответ 1
Если ваш Таймер является объектом уровня приложения, нет ничего плохого в том, чтобы сделать его частным статическим членом вашего основного класса. В любом случае, что бы я сделал.
В документации System.Threading.Timer
говорится, что я должен сохранить ссылку на него, чтобы избежать сбора мусора. Но где я должен это делать? Мой main
очень прост, что я не знаю, где сохранить ссылку:
class Program {
static void Main() {
new System.Threading.Thread(myThreadStart).Start();
new System.Threading.Timer(myTimerCallback, new MyStateObject(), 0, 5000);
}
}
Я думал о сохранении ссылки в поле static
в классе Program
, предполагая, что поля static
не собираются до конца приложения. Но я не уверен, что это лучший способ сделать это, поэтому я буду благодарен за ваш совет.
Если ваш Таймер является объектом уровня приложения, нет ничего плохого в том, чтобы сделать его частным статическим членом вашего основного класса. В любом случае, что бы я сделал.
EDIT: Мой оригинальный ответ - мусор. Действительно мусор. Я сохранил его здесь, чтобы объяснить, почему это мусор, хотя - это в комментариях, но они были бы удалены с ответом.
GC.KeepAlive только гарантирует, что ссылка обрабатывается как корень, пока после вызова. В коде внизу этого ответа метод GC.KeepAlive будет вызываться немедленно, а затем таймер будет по-прежнему иметь право на сбор мусора. Поскольку вновь созданный поток является потоком переднего плана, приложение будет работать до тех пор, пока оно будет живым (тогда как таймер использует фоновый поток, что не препятствует выходу программы). Это означает, что основной метод завершается, но приложение необходимо продолжать работать.
Возможно, более простым решением было бы запустить myThreadStart
в основном потоке, вместо того, чтобы создавать новый, а затем позволить основному потоку умереть. Другими словами, простым решением было бы следующее:
using System.Threading;
class Program {
static void Main() {
Timer timer = new Timer(myTimerCallback,
new MyStateObject(), 0, 5000);
myThreadStart();
GC.KeepAlive(timer);
}
}
Я предполагаю, что реальный код более сложный, хотя - в этом случае использование частной статической переменной, как предлагается в других ответах, вероятно, является способом выхода. Однако это будет зависеть от использования. Я лично предпочитаю не создавать статическое поле только для того, чтобы предотвратить сбор чего-либо, если есть альтернатива (например, выше), но иногда это практически единственный способ сделать это.
Исходный (плохой) ответ:
Если вы действительно хотите выделить его в Main, вы можете использовать GC.KeepAlive:
using System.Threading;
class Program {
static void Main() {
new Thread(myThreadStart).Start();
Timer timer = new Timer(myTimerCallback,
new MyStateObject(), 0, 5000);
GC.KeepAlive(timer);
}
}
Я думаю, что это нормально, это личное статическое поле вашего класса.
Я бы сохранил эту ссылку как статическое поле, а не играл с сборщиком мусора.