开发者

Action delay extension method not working

开发者 https://www.devze.com 2023-04-13 09:44 出处:网络
I\'m trying to create a handy extension method to Action to basically run that action after a delay: So far my extension looks like this

I'm trying to create a handy extension method to Action to basically run that action after a delay: So far my extension looks like this

    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());
    }

I have a function I call that in turn uses these extensions

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

Which I call like this:

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

But it all seems to drop down a whole and the action never fires. Where am I going wrong?

Edit 17-11-11 2300hrs:

I removed the generic extension method as it's not relevant to this example.

Also posting comment here as it doesn't format the code clearly in comments

If instead of the call

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

I do this directly:

Task t = Task.Factory.StartNew(() => { Thread.Sleep(1500); }, Token, TaskCreationOptions.None, TaskScheduler.Default); 
t.ContinueWith(() => { _SomeFunction(SomeArgs); }, Token, TaskContinuationOptions.None, TaskScheduler.FromCur开发者_开发技巧rentSynchronizationContext()); 

It works ok (sorry if there's any syntax error there I have done it from memory) So I beleive my issue is in the handling of the Action which Nick Butler's Answer eludes to


Your continuations are returning the DelayedAction delegate, not invoking it:

t.ContinueWith(_ => DelayedAction(), Token, ...


If Tasks is not a strong requirement I would suggest use System.Threading.Timer which has built in "delay" feature, constructor looks like:

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

MSDN:

dueTime Type: System.Int32 The amount of time to delay before callback is invoked, in milliseconds. Specify Timeout.Infinite to prevent the timer from starting. Specify zero (0) to start the timer immediately.

! Also what is important you can change this delay after the construction stage.


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);                        
        }  


Of course you can do it with tasks. The problem was, that you called StartNew of TaskFactory, which immediatley starts your task.

Try it in this way - this should work:

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();
} 
0

精彩评论

暂无评论...
验证码 换一张
取 消