Как я могу гарантировать, что одна активная задача всегда будет уничтожена и заменена при каждом вызове метода, который запускает задачу.уведомление, ожидающее отображения (последнего вызывающего), независимо от того, сколько раз вызывается метод (SetFutureNotification) (или как быстро).
При отладке и вызове метода (быстро), скажем, 5 раз, я вижу очень странные результаты.
Например: 2-я задача вызывающих абонентов запущена, а последующие задачи вызывающих абонентов отменены (завершены)).
Ожидаемое поведение для выполнения Задачи последнего вызывающего абонента (5-й вызывающий) и отмены (прекращения) всех предыдущих вызывающих Задач.
Помещая небольшую задержку между каждым из 5 тестовых вызовов (500 мс), я получаю желаемый результат, однако я хочу научиться правильному подходу.
public static class NotificationsHelper
{
private static CancellationTokenSource _cts = new CancellationTokenSource();
// Set Future Notification (From outside this class).
// If called multiple times, the existing task should be killed and a new task replaces it.
public static void SetFutureNotification(string notificationText, DateTime notificationDateTime, Action<string> notificationAction)
{
CancelNotification();
_cts = new CancellationTokenSource();
Task.Run(async () =>
{
while (!_cts.Token.IsCancellationRequested)
{
await Task.Delay(1000, _cts.Token);
if (DateTime.Now > notificationDateTime)
{
notificationAction?.Invoke(notificationText);
_cts.Cancel();
}
}
}, _cts.Token);
}
// Cancel Active Future Notification (From outside this class).
public static void CancelNotification()
{
if (_cts != null && _cts.Token != null && _cts.Token.CanBeCanceled == true)
{
_cts.Cancel();
}
}
}
Редактировать: я переформатировал свой код, чтобы проверить предложенный Олегом ответ (ниже), добавив Id для отслеживания задач.Это подтвердило желаемый результат:
public static class NotificationsHelper
{
private static int _counter = 0;
private static CancellationTokenSource _cts;
// Set Future Notification (From Anywhere).
// If called multiple times, the existing task should be killed and a new task replaces it.
public static void SetFutureNotification(string notificationText, DateTime notificationDateTime, Action<string> notificationAction)
{
_counter += 1;
var id = _counter.ToString();
Console.WriteLine("Method Called: " + id);
CancelNotification();
_cts = new CancellationTokenSource();
var cts = _cts; // I'm local cts and will be captured by one task only
Task.Run(async () =>
{
while (!cts.Token.IsCancellationRequested)
{
await Task.Delay(1000, cts.Token);
if (DateTime.Now > notificationDateTime)
{
notificationAction?.Invoke(notificationText);
cts.Cancel();
}
Console.WriteLine("Task active: " + id);
}
}, cts.Token).ContinueWith(t => { Console.WriteLine("Task exited: " + id); });
}
// Cancel Notification (From Anywhere).
public static void CancelNotification()
{
if (_cts != null && _cts.Token != null && _cts.Token.CanBeCanceled == true)
{
_cts.Cancel();
}
}
}