动作延迟扩展方法不起作用

发布于 2024-12-10 09:40:46 字数 1418 浏览 1 评论 0原文

我正在尝试为 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 2300hrs:

我删除了通用扩展方法,因为它与本示例无关。

还在这里发布评论,因为它没有在注释中清楚地格式化代码

如果我直接这样做而不是调用

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

它工作正常(抱歉,如果有任何语法错误,我已经从内存中完成了)所以我相信我的问题在于尼克·巴特勒的答案回避的动作的处理

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.FromCurrentSynchronizationContext()); 

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

日记撕了你也走了 2024-12-17 09:40:46

您的延续将返回 DelayedAction 委托,而不是调用它:

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

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

t.ContinueWith(_ => DelayedAction(), Token, ...
浮世清欢 2024-12-17 09:40:46

如果任务不是一个强烈的要求,我建议使用 System.Threading。内置“延迟”功能的计时器,构造函数如下:

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

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);                        
        }  
把人绕傻吧 2024-12-17 09:40:46

当然,你可以通过任务来完成。问题是,您调用了 TaskFactory 的 StartNew,它会立即启动您的任务。

以这种方式尝试 - 这应该有效:

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

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();
} 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文