【问题标题】:What's the most concise way to create a Task that never returns?创建永不返回的任务的最简洁方法是什么?
【发布时间】:2018-02-07 18:59:41
【问题描述】:

出于测试目的,我需要在接口上模拟一个Task-returning 方法,以返回一个永远不会运行延续的任务。这是我到目前为止的代码:

// FooTests.cs

[Test]
public void Foo()
{
    var yielder = Substitute.For<IYielder>();
    yielder.YieldAsync().Returns(ThreadingUtilities.NeverReturningTask);

    ...
}

// ThreadingUtilities.cs

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

namespace Repository.Editor.Android.UnitTests.TestInternal.Threading
{
    internal static class ThreadingUtilities
    {
        public static Task NeverReturningTask { get; } = CreateNeverReturningTask();

        private async static Task CreateNeverReturningTask()
        {
            await new StopAwaitable();
            Debug.Fail("Execution shouldn't reach here.");
        }
    }
}

// StopAwaitable.cs

using System;
using System.Diagnostics;
using System.Runtime.CompilerServices;

namespace Repository.Editor.Android.UnitTests.TestInternal.Threading
{
    internal struct StopAwaitable : INotifyCompletion
    {
        public bool IsCompleted => false;

        public StopAwaitable GetAwaiter() => this;

        public void GetResult()
        {
            Debug.Fail("The continuation shouldn't have been posted!");
        }

        public void OnCompleted(Action continuation)
        {
            // Ignore the continuation.
        }
    }
}

在这里,我创建了一个自定义等待类型,它只是忽略传递给它的延续——await new StopAwaitable() 与来自同步方法的return 具有基本相同的效果。然后,我在 async Task 方法中等待它,创建一个永远不会运行延续的 Task 对象。

我的问题是,这是最简洁/清晰的方法吗?有没有其他方法可以创建这样一个不涉及自定义等待的任务,这会让不熟悉async 工作原理的人感到困惑?

【问题讨论】:

  • 在测试代码中经常出现你想要快速'n'dirty解决方案的情况,我很高兴有人已经问过并回答了这个

标签: c# .net asynchronous async-await task


【解决方案1】:

我希望我在这里正确地阅读了这个问题......

return new System.Threading.Tasks.TaskCompletionSource<object>().Task;
  1. 返回由任务完成源创建的任务。
  2. 切勿将源设置为完成。

永远不会调用延续,await 将永远“阻塞”。

【讨论】:

    【解决方案2】:

    你可以使用:

    var taskThatNeverReturns = Task.Delay(Timeout.Infinite);
    

    docs 声明参数代表:

    在完成返回任务之前等待的毫秒数,或 -1 无限期等待。

    Timeout.Infinite 是一个常量字段,值为-1

    【讨论】:

    • @JamesKo 如果出于清理目的需要结束这个无限的Task,请将CancellationToken 传递给Task.Delay 重载!
    猜你喜欢
    • 1970-01-01
    • 2016-06-19
    • 1970-01-01
    • 2017-02-09
    • 2011-04-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多