Метод расширения задержки действия не работает - PullRequest
4 голосов
/ 17 октября 2011

Я пытаюсь создать удобный метод расширения для Action, чтобы в основном запускать это действие с задержкой: пока мое расширение выглядит так

    public static void DelayAction(this Action DelayedAction, int millisecondDelay, CancellationToken Token)
    {
        Task t = Task.Factory.StartNew(() => { Thread.Sleep(millisecondDelay); }, Token, TaskCreationOptions.None, TaskScheduler.Default);            
        t.ContinueWith(_ => DelayedAction, Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
    }

У меня есть функция, которую я вызываю и которая в свою очередь используетэти расширения

    private void DelayTask(Action ActiontoDelay, int millisecondDelay)
    {
        ActiontoDelay.DelayAction(millisecondDelay, _TokenSource.Token);
    } 

Которые я называю так:

    DelayTask(() => { _SomeFunction(SomeArgs); }, 1500);

Но все это, кажется, падает в целом, и действие никогда не запускается.Куда я иду не так?

Редактировать 17-11-11 23:00:

Я удалил универсальный метод расширения, так как он не относится к этому примеру.

Также публикуем комментарий здесьпоскольку он не форматирует код четко в комментариях

Если вместо вызова

DelayTask(() => { _SomeFunction(SomeArgs); }, 1500); 

я делаю это напрямую:

Task t = Task.Factory.StartNew(() => { Thread.Sleep(1500); }, Token, TaskCreationOptions.None, TaskScheduler.Default); 
t.ContinueWith(() => { _SomeFunction(SomeArgs); }, Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext()); 

Работает нормально (извинитеесли там есть какая-то синтаксическая ошибка, я сделал это из памяти) Так что я полагаю, что моя проблема заключается в обработке действия, которое ответ Ника Батлера не дает

Ответы [ 3 ]

5 голосов
/ 17 октября 2011

Ваши продолжения возвращают делегата DelayedAction, не вызывая его:

t.ContinueWith(_ => DelayedAction(), Token, ...
3 голосов
/ 17 октября 2011

Если задачи не являются строгими требованиями, я бы предложил использовать System.Threading.Timer со встроенной функцией «задержки», конструктор выглядит так:

public Timer(
    TimerCallback callback,
    Object state,
    int dueTime,
    int period
)

MSDN :

dueTime Тип: System.Int32 Время задержки до вызова, в миллисекундах.Укажите Timeout.Infinite, чтобы предотвратить запуск таймера.Укажите ноль (0) для немедленного запуска таймера.

! Также важно изменить эту задержку после этапа строительства.


public static void DelayAction<T>(
            this Action<T> delayedAction, 
            T argument, 
            int millisecondDelay, 
            CancellationToken cancellationToken)
        {
            // Timeout.Infinite to disable periodic signaling.
            var timer = new System.Threading.Timer(x =>
                                {
                                   cancellationToken.ThrowIfCancellationRequested();
                                   delayedAction.Invoke(argument);
                                }, 
                                null, 
                                millisecondDelay, 
                                Timeout.Infinite);                        
        }  
0 голосов
/ 17 октября 2011

Конечно, вы можете сделать это с помощью задач.Проблема заключалась в том, что вы вызвали StartNew из TaskFactory, который немедленно запускает вашу задачу.

Попробуйте это так - это должно работать:

public static void DelayAction<T>(this Action<T> DelayedAction, int millisecondDelay, CancellationToken Token)
{
    var task = new Task(t => { Thread.Sleep(millisecondDelay); }, null, Token);
    task.ContinueWith(t => DelayedAction, Token, TaskContinuationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
    task.Start();
} 
...