我应该总是完成一个TaskCompletionSource吗?

时间:2014-12-02 16:41:01

标签: c# task-parallel-library async-await taskcompletionsource

如果TaskCompletionSource永远不会完成(TaskTaskCompletionSourceSetCancelled,则SetException及其SetResult会发生什么?被叫吗?Task永远存在,因为它永远不会完成吗?

在下面的例子中,我有一个参数化测试的简化版本。如果超时(MyEevent未在1000毫秒内调用),则TaskCompletionSourcetcs)永远不会完成。我有很多像这样的测试。我是否需要进行任何类型的清理(例如,确保调用tcs.SetCancelled())。?

[Theory]
[InlineData("aa")]
[InlineData(2)]
[InlineData(true)]
[InlineData(null)]
public async Task RaiseMyEvent_RaisesMyEvent_WithOriginalValue(object value)
{
    var sut = new Thing();
    var tcs = new TaskCompletionSource<object>();
    sut.MyEvent += (_, args) => tcs.SetResult(args.Value);

    sut.RaiseMyEvent(value);

    tcs.Task.Should().BeSameAs(await Task.WhenAny(Task.Delay(1000), tcs.Task), "MyEvent should be raised within 1000ms");
    tcs.Task.Result.Should().Be(value);
}

虽然我们对此有所了解,有什么方法可以改进上述测试(例如,使其更简洁/简单/可读)?

1 个答案:

答案 0 :(得分:5)

  

我是否需要进行任何类型的清理(例如,确保调用tcs.SetCancelled())?

使用TaskCompletionSource<T>不需要任何清理。事实上,它甚至不承认任何清理。所以你的问题的答案是“不”。

TaskCompletionSource<T>只是一个概念上简单的数据结构,允许您最多推送 一个东西(T类型的结果,例外或者消除)。它的Task属性公开了一个Task<T>,它只是这个承诺的单个事物的包装器,将来会被推入TaskCompletionSource<T>。它不使用任务池。

永远不要将任何内容推入TaskCompletionSource<T>是完全有效的。这恰好对应于将永远“运行”并永远不会完成的Task<T>