Могу ли я использовать Threading.Timer в обратном вызове?
Я использую Threading.Timer
, лайк:
new Timer(new TimerCallback(y=>
{
try
{
Save(Read(DateTime.Now));
// here i want to dispose this timer
}
catch
{
}
}),null,100000,10000);
Как я могу избавиться от этого таймера внутри обратного вызова. или обходной путь? Обновление: позвольте мне объяснить ситуацию. Я хочу попробовать вызвать метод "Сохранить", пока он выдает исключение. Если это работает, мне нужно остановить таймер.
5 ответов
Попробуй это:
Timer timer = null;
timer = new Timer(new TimerCallback(y =>
{
try
{
Save(Read(DateTime.Now));
// here i want to dispose this timer
timer.Dispose();
}
catch
{
}
}));
timer.Change(10000, 10000);
РЕДАКТИРОВАТЬ:
Я немного изменил приведенный выше код в соответствии с предложением Чу. Обратите внимание, что если TimerCallback вызывается одновременно различными событиями таймера, Timer.Dispose
может быть вызван несколько раз. К счастью, Timer
не заботится, утилизируется ли он несколько раз.
Вот лучший способ сделать это. Когда вы используете конструктор только с одним параметром (TimerCallback), состоянием, передаваемым обратному вызову, будет сам таймер.
Timer timer = new Timer(o =>
{
((Timer)o).Dispose();
//Your code here
});
//Start the timer
timer.Change(100000,10000);
Вот пример из документации MSDN:
public void StartTimer(int dueTime)
{
Timer t = new Timer(new TimerCallback(TimerProc));
t.Change(dueTime, 0);
}
private void TimerProc(object state)
{
// The state object is the Timer object.
Timer t = (Timer) state;
t.Dispose();
Console.WriteLine("The timer callback executes.");
}
http://msdn.microsoft.com/en-us/library/ms149618(v=vs.110).aspx
Вам нужно сохранить ссылку на таймер в переменной -
public class MyClass
{
private Timer _timer;
public void StartTimer()
{
_timer = new Timer(new TimerCallback(y=>{
try
{
Save(Read(DateTime.Now));
_timer.Dispose();
}
catch {
}
}),null,100000,10000);
}
}
Примечание. Это непроверенный код. Пожалуйста, проверьте, работает ли это, и обновите.
Вам нужно будет где-то сохранить ссылку на таймер и передать ее в качестве состояния самому объекту таймера. Попробуйте создать класс примерно так:
public class TimerContainer
{
public Timer Timer { get; set; }
}
Затем используйте его в вашем методе так:
Action<object> tcb = state =>
{
var container = (TimerConatiner)state;
try
{
Save(Read(DateTime.Now));
container.Timer.Dispose();
}
catch
{
// whatever...
}
};
var container = new TimerContainer();
container.Timer = new Timer(tcb, container, 100000, 10000);
Будьте осторожны, если вы используете многопоточность или многозадачность! Если это так, то здесь вы - код и решение для экстензора метода CancelAfter (.net 4.0):
private static object syncObj = new object();
public static void CancelAfter(this CancellationTokenSource source, int timeoutMilliseconds, Action code = null)
{
if (timeoutMilliseconds == 0) return; // No timeout
if (source == null)
{
throw new NullReferenceException();
}
if (timeoutMilliseconds < -1)
{
throw new ArgumentOutOfRangeException("timeout");
}
Timer timer = new Timer(delegate(object self)
{
lock (syncObj)
{
try
{
if (null != code)
code.Invoke();
source.Cancel();
((IDisposable)self).Dispose();
}
catch (ObjectDisposedException)
{
}
}
});
timer.Change(timeoutMilliseconds, -1);
}
}
С уважением, Хуанлу, ЭльГерре