如何在手动创建的任务中调用异步方法?

时间:2017-09-16 20:02:42

标签: c# .net asynchronous task

我需要在RxJS中实现类似冷可观察对象的东西(只是一个标准的Observable)。我需要在我通过构造函数创建的任务中调用异步方法(new Task())。我需要实现这个,因为在执行任何异步代码之前,我想做一些非常特定于我的项目的东西。所以我想收到一个尚未启动的任务,我可以稍后手动启动。

到目前为止,我做出了以下决定,令我惊讶的是它不起作用!

class Program
{
    static void Main(string[] args)
    {
        var task1 = CallApi(() => t.Go());
        var task2 =  CallApi2(() => t.Go());


        task1.Start();
        task2.Start();

    }



    public static Task<T> CallApi<T>(Func<Task<T>> function)
    {
        if (function == null)
        {
            throw new ArgumentNullException(nameof(function));
        }


        return new Task<Task<T>>(async () =>
        {
            return await function();
        }).Unwrap();


    }

    public static Task<T> CallApi2<T>(Func<Task<T>> function)
    {
        if (function == null)
        {
            throw new ArgumentNullException(nameof(function));
        }

        var tcs = new TaskCompletionSource<T>();

        var resultTask = new Task<Task<T>>(() =>
        {
            var t = function();

            t.ContinueWith(
                task => {
                    tcs.SetResult(task.Result);
                },
                TaskContinuationOptions.OnlyOnRanToCompletion
            );

            t.ContinueWith(
                task => {
                    tcs.SetCanceled();
                },
                TaskContinuationOptions.OnlyOnCanceled
            );

            t.ContinueWith(
                task => {
                    tcs.SetException(task.Exception);

                },
                TaskContinuationOptions.OnlyOnFaulted
            );
            return tcs.Task;
        });

        return resultTask.Unwrap();

    }
}

调用Unwrap或使用TaskCompletionSource似乎在WaitingForActivation状态下创建一个任务。在这种状态下调用任务上的Start方法会引发我的异常,即:

  

启动可能不会在承诺式任务上调用。

因此,.NET很可能区分特殊类型的任务 - 承诺式任务。

总之,我的问题是:

  1. 这些承诺风格的任务是什么意思?

  2. 我怎样才能做我想做的事?

1 个答案:

答案 0 :(得分:2)

Promise样式任务是不基于线程的任务,它们基于事件,对于TaskCompletionSource&#34;事件&#34;是调用SetResultSetCanceledSetException

的行为

要接收尚未启动的任务,您可以稍后手动启动,只需按住Func<Task<T>>,然后评估该功能以便在以后的某个时间启动任务。这可以很简单地完成。

    public void Example()
    {
        Func<Task<T>> func1 = () => t.Go();

        //Do other work

        Task<T> task1 = func1(); //t.Go() is not called until this point then the task starts.

    }