Eli*_*bel 71

使用NuGet 的Microsoft.Bcl.Async包,它有TaskEx.Delay.


Ser*_*rvy 60

您可以使用a 在4.0中Timer创建Delay方法:

public static Task Delay(double milliseconds)
{
    var tcs = new TaskCompletionSource<bool>();
    System.Timers.Timer timer = new System.Timers.Timer();
    timer.Elapsed+=(obj, args) =>
    {
        tcs.TrySetResult(true);
    };
    timer.Interval = milliseconds;
    timer.AutoReset = false;
    timer.Start();
    return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)

  • @EdwardBrey`Timer`类专门在内部处理它,以确保它的用户不需要在它的生命周期内保持对它的引用.只要计时器当前正在运行,它就会从根位置添加对自身的引用,然后在它不再运行时将其删除. (10认同)
  • 这不会造成竞争条件吗?如果计时器对象碰巧在计时器到期之前收集了垃圾,那么似乎永远不会调用`TrySetResult`. (2认同)

Qry*_*taL 26

using System;
using System.Threading;
using System.Threading.Tasks;

class Program
{
    static void Main()
    {
        Delay(2000).ContinueWith(_ => Console.WriteLine("Done"));
        Console.Read();
    }

    static Task Delay(int milliseconds)
    {
        var tcs = new TaskCompletionSource<object>();
        new Timer(_ => tcs.SetResult(null)).Change(milliseconds, -1);
        return tcs.Task;
    }
}
Run Code Online (Sandbox Code Playgroud)

如何在4.0中实现Task.Delay一节

  • 我将这个例子添加到你的答案中,以防链接因某种原因而死亡. (3认同)
  • @Fulproof他写的是使用LinqPad,它为`object`添加了一个扩展方法,用于输出它的`ToString`方法的值.请注意,他没有在实际实现中使用它,也没有使用任何其他非库方法,只是测试它的示例函数. (2认同)

Gus*_*dor 6

下面是可取消的Task.Delay实现的代码和示例工具.您可能对该Delay方法感兴趣:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DelayImplementation
{
    class Program
    {
        static void Main(string[] args)
        {
            System.Threading.CancellationTokenSource tcs = new System.Threading.CancellationTokenSource();

            int id = 1;
            Console.WriteLine(string.Format("Starting new delay task {0}. This one will be cancelled.", id));
            Task delayTask = Delay(8000, tcs.Token);
            HandleTask(delayTask, id);

            System.Threading.Thread.Sleep(2000);
            tcs.Cancel();

            id = 2;
            System.Threading.CancellationTokenSource tcs2 = new System.Threading.CancellationTokenSource();
            Console.WriteLine(string.Format("Starting delay task {0}. This one will NOT be cancelled.", id));
            var delayTask2 = Delay(4000, tcs2.Token);
            HandleTask(delayTask2, id);

            System.Console.ReadLine();
        }

        private static void HandleTask(Task delayTask, int id)
        {
            delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was cancelled.", id)), TaskContinuationOptions.OnlyOnCanceled);
            delayTask.ContinueWith(p => Console.WriteLine(string.Format("Task {0} was completed.", id)), TaskContinuationOptions.OnlyOnRanToCompletion);
        }

        static Task Delay(int delayTime, System.Threading.CancellationToken token)
        {
            TaskCompletionSource<object> tcs = new TaskCompletionSource<object>();

            if (delayTime < 0) throw new ArgumentOutOfRangeException("Delay time cannot be under 0");

            System.Threading.Timer timer = null;
            timer = new System.Threading.Timer(p =>
            {
                timer.Dispose(); //stop the timer
                tcs.TrySetResult(null); //timer expired, attempt to move task to the completed state.
            }, null, delayTime, System.Threading.Timeout.Infinite);

            token.Register(() =>
                {
                    timer.Dispose(); //stop the timer
                    tcs.TrySetCanceled(); //attempt to mode task to canceled state
                });

            return tcs.Task;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)