Ответ 1
timer.Start()
только запускает таймер, но сразу возвращается, когда таймер работает в фоновом режиме. Таким образом, между установкой текста меток на first
и second
паузы почти не происходит. То, что вы хотите сделать, это подождать, пока отметит таймер, и только затем обновить метку еще раз:
void timer_Tick(object sender, EventArgs e)
{
timer.Stop();
label1.Text = "second";
}
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "first";
timer.Start();
}
Btw. вы не должны устанавливать timer.Enabled
в true, вы уже timer.Start()
таймер, используя timer.Start()
.
Как уже упоминалось в комментариях, вы можете поместить создание таймера в метод, например (обратите внимание: это не проверено):
public void Delayed(int delay, Action action)
{
Timer timer = new Timer();
timer.Interval = delay;
timer.Tick += (s, e) => {
action();
timer.Stop();
};
timer.Start();
}
И тогда вы можете просто использовать его так:
private void button1_Click(object sender, EventArgs e)
{
label1.Text = "first";
Delayed(2000, () => label1.Text = "second");
}
Последующие действия
Использует ли Delayed утечку памяти (эталонная утечка)?
Подписка на событие всегда создает двухстороннюю ссылку.
В этом случае
timer.Tick
получает ссылку на анонимную функцию (лямбда). Эта функция поднимает локальныйtimer
переменной, хотя это ссылка, а не значение, и содержит ссылку на переданный в делетете действий. Этот делегат будет содержать ссылку наlabel1
, член экземпляраForm
. Так есть ли циркулярная ссылка отTimer
кForm
?Я не знаю ответа, мне это сложно понять. Поскольку я не знаю, я бы удалил использование лямбда в
Delayed
, сделав его правильным методом и имея его, в дополнение к остановке таймера (который является параметромsender
метода), также удалите событие.
Обычно лямбды не создают проблем для сбора мусора. В этом случае экземпляр таймера существует только локально, а ссылка в лямбда не мешает сборку мусора собирать экземпляры (см. Также этот вопрос).
Я действительно проверил это снова, используя.NET Memory Profiler. Объекты таймера были собраны просто отлично, и утечки не произошло. Профилировщик дал мне предупреждение, что есть случаи, когда "[...] были собраны мусор, не будучи должным образом удалены". Однако удаление обработчика событий (путем ссылки на него) не исправить. Изменение снятой ссылки таймера на (Timer)s
тоже не изменилось.
То, что помогло, очевидно, в том, чтобы вызвать timer.Dispose()
в обработчике событий после остановки таймера, но Id аргументирует, действительно ли это необходимо. Я не думаю, что предупреждение/примечание профилировщика критично.