AFAIK,它所知道的只是在某些时候,它的SetResult或SetException方法被调用来完成通过Task属性暴露的Task<T>。

换句话说,它充当Task<TResult>及其完成的生产者。

我在这里看到了一个例子:

如果我需要一种方法来异步执行Func<T>,并有一个任务<T> 来表示这个操作。

public static Task<T> RunAsync<T>(Func<T> function) 
{ 
    if (function == null) throw new ArgumentNullException(“function”); 
    var tcs = new TaskCompletionSource<T>(); 
    ThreadPool.QueueUserWorkItem(_ => 
    { 
        try 
        {  
            T result = function(); 
            tcs.SetResult(result);  
        } 
        catch(Exception exc) { tcs.SetException(exc); } 
    }); 
    return tcs.Task; 
}

如果我没有Task.Factory.StartNew - 但是我有task。factory。startnew。

问题:

有人能举例说明一个与TaskCompletionSource直接相关的场景吗 而不是假设没有task。factory。startnew ?


当前回答

这可能是过于简化的事情,但TaskCompletion源代码允许等待一个事件。从tc开始。SetResult只在事件发生时设置,调用者可以等待任务。

观看这段视频了解更多:

http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Lucian03-TipsForAsyncThreadsAndDatabinding

其他回答

似乎没有人提到,但我想单元测试也可以被认为是真实的生活。

我发现TaskCompletionSource在使用异步方法模拟依赖时非常有用。

在实际被测程序中:

public interface IEntityFacade
{
  Task<Entity> GetByIdAsync(string id);
}

在单元测试中:

// set up mock dependency (here with NSubstitute)

TaskCompletionSource<Entity> queryTaskDriver = new TaskCompletionSource<Entity>();

IEntityFacade entityFacade = Substitute.For<IEntityFacade>();

entityFacade.GetByIdAsync(Arg.Any<string>()).Returns(queryTaskDriver.Task);

// later on, in the "Act" phase

private void When_Task_Completes_Successfully()
{
  queryTaskDriver.SetResult(someExpectedEntity);
  // ...
}

private void When_Task_Gives_Error()
{
  queryTaskDriver.SetException(someExpectedException);
  // ...
}

毕竟,TaskCompletionSource的这种用法似乎是“不执行代码的任务对象”的另一种情况。

我主要在只有基于事件的API可用时使用它(例如Windows Phone 8套接字):

public Task<Args> SomeApiWrapper()
{
    TaskCompletionSource<Args> tcs = new TaskCompletionSource<Args>(); 

    var obj = new SomeApi();

    // will get raised, when the work is done
    obj.Done += (args) => 
    {
        // this will notify the caller 
        // of the SomeApiWrapper that 
        // the task just completed
        tcs.SetResult(args);
    }

    // start the work
    obj.Do();

    return tcs.Task;
}

所以当它与c# 5的async关键字一起使用时尤其有用。

Blazor的WebAssemblyHost也使用这个来防止. net虚拟机停止。

await new TaskCompletionSource().Task;

对我来说,使用TaskCompletionSource的一个经典场景是,我的方法可能不必执行耗时的操作。它允许我们做的是选择我们想要使用新线程的特定情况。

使用缓存就是一个很好的例子。你可以有一个GetResourceAsync方法,它在缓存中查找所请求的资源,并在找到资源时立即返回(不使用新线程,通过使用TaskCompletionSource)。只有在没有找到资源的情况下,我们才会使用一个新的线程,并使用Task.Run()检索它。

这里可以看到一个代码示例:如何有条件地使用任务异步运行代码

这可能是过于简化的事情,但TaskCompletion源代码允许等待一个事件。从tc开始。SetResult只在事件发生时设置,调用者可以等待任务。

观看这段视频了解更多:

http://channel9.msdn.com/Series/Three-Essential-Tips-for-Async/Lucian03-TipsForAsyncThreadsAndDatabinding