c# - 如何在 C# 中创建和使用自定义 Awaitable?

标签 c# .net async-await

我正在尝试实现自定义 awaiteable 以执行 await Thread.SleepAsync() 而无需创建任何其他线程。

这是我得到的:

    class AwaitableThread : INotifyCompletion
    {
        public AwaitableThread(long milliseconds)
        {
            var timer = new Timer(obj => { IsCompleted = true; }, null, milliseconds, Timeout.Infinite);
        }

        private bool isCompleted = false;

        public bool IsCompleted
        {
            get { return isCompleted; }
            set { isCompleted = value; }
        }

        public void GetResult()
        {}

        public AwaitableThread GetAwaiter() { return this; }

        public void OnCompleted(Action continuation)
        {
            if (continuation != null)
            {
                continuation();
            }
        }
    }

下面是 sleep 的工作原理:

    static async Task Sleep(int milliseconds)
    {
        await new AwaitableThread(milliseconds);
    }

问题是这个函数立即返回,即使在 OnCompleted 中,IsCompleted 仍然是 false。

我做错了什么?

最佳答案

为生产使用完全实现可等待模式是一项棘手的工作——您需要捕获执行上下文等。 Stephen Toub's blog post对此有更多的细节。在许多情况下,搭载 Task<T> 更容易或 Task , 可能使用 TaskCompletionSource .例如,在您的情况下,您可以编写相当于 Task.Delay 的内容像这样:

public Task MyDelay(int milliseconds)
{
    // There's only a generic TaskCompletionSource, but we don't really
    // care about the result. Just use int as a reasonably cheap version.
    var tcs = new TaskCompletionSource<int>();

    Timer timer = new Timer(_ => tcs.SetResult(0), null, milliseconds,
                            Timeout.Infinite);
    // Capture the timer variable so that the timer can't be garbage collected
    // unless the task is (in which case it doesn't matter).
    tcs.Task.ContinueWith(task => timer = null);

    return tcs.Task;
}

您现在可以 await该任务,就像您可以等待 Task.Delay 的结果一样.

关于c# - 如何在 C# 中创建和使用自定义 Awaitable?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13430266/

相关文章:

linq - 如何使用LINQ异步调用带有子记录的数据库?

c# - 异步下载多个文件并等待所有文件完成,然后再执行其余代码

c# - 等待一个可观察的

c# - 如何将类列表传递给接口(interface)列表?

c# - Microsoft 如何决定在 C# 中将方法设为静态/成员?

.Net - 模拟和混淆

c# - 使用 '#region' 作为快速修复以避免重构为更小的函数

c# - 使用 TimeZoneInfo.ConvertTimeToUtc(DateTime, TimeZoneInfo) 方法时,在 DST 结束日期将时间从本地时间转换为 UTC 的问题

c# - 实体数据网格: best way to add computed values?

.net - 服务契约(Contract)属性中的命名空间 url 是什么