Как вызвать асинхронный метод внутри задачи, созданной вручную?

Мне нужно реализовать что-то вроде объекта с холодным наблюдением в 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 ответ

Решение

Задачи стиля Promise - это задачи, которые не основаны на потоках, они основаны на событиях, для TaskCompletionSource "событие" - это акт вызова SetResult, SetCanceled или же SetException

Чтобы получить задачу, которая еще не запущена и которую можно запустить вручную чуть позже, просто удерживайте 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.

    }
Другие вопросы по тегам