C# 如何返回任务<;T>;不期而至

C# 如何返回任务<;T>;不期而至,c#,async-await,C#,Async Await,如果一个方法首先调用多个task返回方法,然后返回包含以前调用结果的某种类型,而不使用wait,是否可以从该方法返回任务 例如,下面是直截了当的: public Task GetAsync()=>FirstOrDefaultAsync(); 但是,我想这样做: public Task<SomeType> GetAsync() { return WhenAll(GetListAsync(), GetCountAsync(), (list, count) =&g

如果一个方法首先调用多个
task
返回方法,然后返回包含以前调用结果的某种类型,而不使用
wait
,是否可以从该方法返回任务

例如,下面是直截了当的:

public Task GetAsync()=>FirstOrDefaultAsync();
但是,我想这样做:

public Task<SomeType> GetAsync()
{
    return WhenAll(GetListAsync(), GetCountAsync(),
        (list, count) => new SomeType { List = list, Count = count });
}
公共任务GetAsync() { var list=GetListAsync();//可以与一起使用

公共任务GetAsync() { var list=GetListAsync(); var count=GetCountAsync(); 返回Task.WhenAll(list,count).ContinueWith(=>newtype2 { List=List.Result, Count=Count.Result, }); } 编辑

正如评论中所建议的那样,你最好只使用
wait
。我还建议你阅读由-

链接的文章,你可以和它一起使用

公共任务GetAsync() { var list=GetListAsync(); var count=GetCountAsync(); 返回Task.WhenAll(list,count).ContinueWith(=>newtype2 { List=List.Result, Count=Count.Result, }); } 编辑


正如评论中所建议的,你最好只使用
wait
。我还建议你阅读由-

链接的帖子坦率地说,问题中的版本是正确的:

公共异步任务GetAsync() { 返回新类型2 { 列表=等待GetListAsync(), Count=等待GetCountAsync(), }; } 我知道你问的是“不使用wait”,但是:避免wait的黑客是次优的;特别是,你几乎不应该使用
ContinueWith
——这是传统的API,
任务
实现现在针对
wait
,而不是
ContinueWith
进行了优化

至于:

因为我读到多次等待对性能不利。我尝试在最后一次呼叫时等待

不;一旦你有了一个不完整的等待,你还有多少就无关紧要了——它们实际上是免费的。一个不完整的等待与零个不完整的等待的问题相当于一个不完整的等待,因此:避免
等待是没有任何好处的

结论:只需使用
wait
,它更简单、更直接,内部结构也为此进行了优化

作为次要优化,您可能需要添加
ConfigureAwait(false)
,即

公共异步任务GetAsync() { 返回新类型2 { List=await GetListAsync().ConfigureAwait(false), Count=await GetCountAsync().ConfigureAwait(false), }; }
或者如果它们应该同时运行,并且实现支持它:

公共任务GetAsync() { var list=GetListAsync(); var count=GetCountAsync(); 返回新的SomeType { 列表=等待列表。配置等待(false), 计数=等待计数。配置等待(false), }; }
坦率地说,问题中已有的版本是正确的:

公共异步任务GetAsync() { 返回新类型2 { 列表=等待GetListAsync(), Count=等待GetCountAsync(), }; }
我知道你问的是“不使用wait”,但是:避免wait的黑客是次优的;特别是,你几乎不应该使用
ContinueWith
——这是传统的API,
任务
实现现在针对
wait
,而不是
ContinueWith
进行了优化

至于:

因为我读到多次等待对性能不利。我尝试在最后一次呼叫时等待

不;一旦你有了一个不完整的等待,你还有多少就无关紧要了——它们实际上是免费的。一个不完整的等待与零个不完整的等待的问题相当于一个不完整的等待,因此:避免
等待是没有任何好处的

结论:只需使用
wait
,它更简单、更直接,内部结构也为此进行了优化

作为次要优化,您可能需要添加
ConfigureAwait(false)
,即

公共异步任务GetAsync() { 返回新类型2 { List=await GetListAsync().ConfigureAwait(false), Count=await GetCountAsync().ConfigureAwait(false), }; }
或者如果它们应该同时运行,并且实现支持它:

公共任务GetAsync() { var list=GetListAsync(); var count=GetCountAsync(); 返回新的SomeType { 列表=等待列表。配置等待(false), 计数=等待计数。配置等待(false), }; }
问题在于,该方法不接受具有不同结果类型的任务。所有任务必须是同一类型的。幸运的是,这很容易解决。whalll
变量bellow等待两个具有不同类型的任务,并返回一个具有组合结果的任务

public static Task<TResult> WhenAll<T1, T2, TResult>(
    Task<T1> task1, Task<T2> task2, Func<T1, T2, TResult> factory)
{
    return Task.WhenAll(task1, task2).ContinueWith(t =>
    {
        var tcs = new TaskCompletionSource<TResult>();
        if (t.IsFaulted)
        {
            tcs.SetException(t.Exception.InnerExceptions);
        }
        else if (t.IsCanceled)
        {
            tcs.SetCanceled();
        }
        else
        {
            tcs.SetResult(factory(task1.Result, task2.Result));
        }
        return tcs.Task;
    }, default, TaskContinuationOptions.ExecuteSynchronously,
        TaskScheduler.Default).Unwrap();
}
公共静态任务(
任务task1、任务task2、Func工厂)
{
返回Task.WhenAll(task1,task2)。继续(t=>
{
var tcs=new TaskCompletionSource();
如果(t.IsFaulted)
{
SetException(t.Exception.innerException);
}
否则,如果(t.IsCanceled)
{
setCancelled();
}
其他的
{
tcs.SetResult(工厂(task1.Result,task2.Result));
}
返回tcs.Task;
},默认值,TaskContinuationOptions.ExecuteSynchronously,
TaskScheduler.Default).Unwrap();
}
它可以这样使用:

public Task<SomeType> GetAsync()
{
    return WhenAll(GetListAsync(), GetCountAsync(),
        (list, count) => new SomeType { List = list, Count = count });
}
公共任务GetAsync() { 返回whalll(GetListAsync(),GetCountAsync(), (list,count)=>newsometype{list=list,count=count}); } 与其他解决方案相比的优势在于处理异常。如果
GetListAsync
GetCountAsync
都失败,则