Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/326.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在手动创建的任务中调用异步方法?_C#_.net_Asynchronous_Task - Fatal编程技术网

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

C# 如何在手动创建的任务中调用异步方法?,c#,.net,asynchronous,task,C#,.net,Asynchronous,Task,我需要在RxJS中实现类似冷可观察对象的东西(只是一个标准可观察对象)。我需要在通过构造函数(newtask())自己创建的任务中调用异步方法。我需要实现这一点,因为在执行任何异步代码之前,我想做一些特定于我的项目的事情。因此,我想接收一个尚未启动的任务,稍后可以手动启动 到目前为止,我做出了以下决定,令我惊讶的是,它没有起作用 class Program { static void Main(string[] args) { var task1 = CallAp

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

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

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();

    }
}
类程序
{
静态void Main(字符串[]参数)
{
var task1=CallApi(()=>t.Go());
var task2=CallApi2(()=>t.Go());
task1.Start();
task2.Start();
}
公共静态任务调用API(Func函数)
{
if(函数==null)
{
抛出新ArgumentNullException(nameof(function));
}
返回新任务(异步()=>
{
返回等待函数();
}).Unwrap();
}
公共静态任务CallApi2(Func函数)
{
if(函数==null)
{
抛出新ArgumentNullException(nameof(function));
}
var tcs=new TaskCompletionSource();
var resultTask=新任务(()=>
{
var t=函数();
t、 继续(
任务=>{
tcs.SetResult(task.Result);
},
TaskContinuationOptions.OnlyOnRanToCompletion
);
t、 继续(
任务=>{
setCancelled();
},
TaskContinuationOptions.OnlyonCancelled
);
t、 继续(
任务=>{
SetException(task.Exception);
},
TaskContinuationOptions.OnlyOnFaulted
);
返回tcs.Task;
});
返回resultTask.Unwrap();
}
}
调用Unwrap或使用TaskCompletionSource似乎会创建处于WaitingForActivation状态的任务。在这种状态下对任务调用Start方法会导致异常情况,即:

不能对承诺式任务调用Start

所以.NET很可能区分了特殊类型的任务——承诺式任务

总之,我的问题是:

  • 这些承诺式任务意味着什么

  • 我怎样才能做我想做的事


  • 承诺式任务是不基于线程的任务,它们基于事件,对于
    TaskCompletionSource
    而言,“事件”是调用
    SetResult
    setcancelled
    SetException

    要接收一个尚未启动的任务,您可以稍后手动启动该任务,只需按住
    Func
    ,然后评估该函数,以便在稍后的时间点启动该任务。这可以很简单地做到

        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.
    
        }
    
    public void示例()
    {
    Func func1=()=>t.Go();
    //做其他工作
    Task task1=func1();//t.Go()直到此时任务才被调用。
    }
    
    承诺式任务是不基于线程的任务,它们基于事件,对于
    TaskCompletionSource
    来说,“事件”是调用
    SetResult
    setcancelled
    SetException

    要接收一个尚未启动的任务,您可以稍后手动启动该任务,只需按住
    Func
    ,然后评估该函数,以便在稍后的时间点启动该任务。这可以很简单地做到

        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.
    
        }
    
    public void示例()
    {
    Func func1=()=>t.Go();
    //做其他工作
    Task task1=func1();//t.Go()直到此时任务才被调用。
    }
    
    这就是我目前所得到的。我刚才使用了一个类似于您的示例中的委托,它确实有效。当我调用它时,它会启动一个任务。但是当我只使用任务时,我想做完全相同的事情。难道不可能吗?冷任务只是保留传递给构造函数的委托,然后使用额外的线程来执行委托。“没有委托”是无法做到这一点的,因为任务的构造函数只接受委托。通过不使用不必要的线程来节省您自己的一些性能,只需自己运行代理即可。您可以在我的问题中看到我尝试这样做。我只是将委托传递给CallApi方法,该方法创建一个“冷”任务。但这项冷酷的任务根本没有开始。它抛出了我说过的异常。你能给我一个不考虑性能问题的方法吗?不,因为我觉得冷任务是一种不合适的方式,不应该使用它,除非你正在编写一个自定义线程调度程序,否则我不会教别人如何做一些我认为不好的事情。只需要使用代理。这个类比有助于解释它吗?您无法启动TaskCompletionSource,因为一旦有人调用3个函数之一
    SetResult
    SetCancelled
    SetException
    时,将任务设置为
    Completed
    ,这只是一个“承诺”。您不能过早地“开始”履行承诺,因为承诺是在调用这3个函数之一后设置一个变量。没有被调用的函数,就没有什么可“启动”的,当调用函数时,它们会在调用过程中设置任务的状态。这就是我目前得到的。我刚才使用了一个类似于您的示例中的委托,它确实有效。当我调用它时,它会启动一个任务。但是当我只使用任务时,我想做完全相同的事情。难道不可能吗?冷任务只是保留传递给构造函数的委托,然后使用额外的线程来执行委托。“没有委托”是无法做到这一点的,因为这是构造函数对TA的唯一要求