我如何从异步方法返回一个列表?



我得到了这段Visual Studio不会抱怨的代码

int fortyTwo = await CalculateAnswerAsync();
Debug.WriteLine(fortyTwo);
async public static Task<int> CalculateAnswerAsync()
{
await Task.Delay(1000);
return 42;
}

我正在返回一个任务,它封装了我在1秒后返回并通过await访问的int 42。所有伟大的。

现在,当我试图将这种方法应用到处理列表的程序区域时,我得到了一个错误:

public List<Payee> Payees { get; set; } = new();
var payeesTask = dataService.GetPayees();
List<Payee> payees = await payeesTask;
Debug.WriteLine(payees.ToString());
public Task<List<Payee>> GetPayees()
{
//Payees is underlined with the red squiggle, boooo
if(Payees.Count != 0) return Payees; 
Payees.Add(new Payee { Id = 0, Name = "Food Lion", DefaultCategoryId = 0, DefaultIsCredit = false });
return Payees;
}
我得到的错误是Cannot implicitly convert type 'System.Collections.Generic.List<MyApp.Model.Payee>' to 'System.Threading.Tasks.Task<System.Collections.Generic.List<MyApp.Model.Payee>>'

我完全理解并同意,除了我的例子返回42不会出错。到底发生了什么事?

简写:GetPayees()方法声明缺少async关键字。

是的,那更像是一种评论。让我们看看我是否可以扩展一下…

方法定义中的async关键字导致编译器做一些工作来围绕您的代码创建任务:IAsyncStateMachine实现和创建该类实例的代码,初始化它并创建要返回的Task<...>对象。这一切看起来都很有趣,虽然有点复杂。

由于您没有将方法声明为async,因此这些都没有完成。相反,您声明了一个简单的方法,该方法期望您返回手动创建或从其他地方获取的Task<List<Payee>>。相反,你试图返回一个原始的List<Payee>,而没有在它周围包装一个任务。

因此,简单的解决方法是将async添加到您的(当前同步的)代码中:
public async Task<List<Payee>> GetPayees() 
{
// need to await something or the compiler complains
await Task.Delay(1);
// rest of your code here...
}

如果你只是在模拟一些在实时代码中正确异步的东西,你可以使用Task.FromResult()来返回一个只保留返回值的缩减任务,或者如果你需要做一些更有趣的事情,那么你可以在Task.Run()中包装同步代码,让它在一个单独的线程上运行。

Task.FromResult():

public Task<List<Payee>> GetPayees()
{
if(Payees.Count == 0)
Payees.Add(new Payee { Id = 0, Name = "Food Lion", DefaultCategoryId = 0, DefaultIsCredit = false });
return Task.FromResult(Payees);
}

Task.Run:

public Task<List<Payee>> GetPayees()
{
return Task.Run(() => 
{
// long-running synchronous code here
Thread.Sleep(250);

if(Payees.Count == 0)
Payees.Add(new Payee { Id = 0, Name = "Food Lion", DefaultCategoryId = 0, DefaultIsCredit = false });
return Task.FromResult(Payees);
};
}

假设你没有测试你的代码如何处理获取收款人列表的延迟,Task.FromResult()可能是更好的选择。

(顺便说一句…难道只有我一个人觉得"食物狮子"这个想法有点奇怪吗?)

最新更新