C# 使用async await ContinueWith在主线程上运行然后调用?

C# 使用async await ContinueWith在主线程上运行然后调用?,c#,multithreading,asynchronous,xamarin.forms,C#,Multithreading,Asynchronous,Xamarin.forms,下面的代码工作得很好。它在UI上显示微调器,使用线程池中的线程启动任务,并运行繁重的操作,一旦完成,逻辑将隐藏微调器在主线程上按预期执行 public void LoadCustomers() { // Update UI to show spinner this.LoadingCustomers = true; Task.Run(async () => { v

下面的代码工作得很好。它在UI上显示微调器,使用线程池中的线程启动任务,并运行繁重的操作,一旦完成,逻辑将隐藏微调器在主线程上按预期执行

    public void LoadCustomers()
    {
        // Update UI to show spinner
        this.LoadingCustomers = true;

        Task.Run(async () =>            
        {
            var customers = await this.custService.GetCustomers();
            // code truncated for clarity

            Device.BeginInvokeOnMainThread(() => 
            {
                // Update UI to hide spinner
                this.LoadingCustomers = false;
            });
        });
    }
我的问题;是否有更好的方法使用ContinueWith/configureWait选项编写此逻辑?使用这些选项似乎会阻塞UI线程。在下面的示例中,UI线程是否应该继续运行UI逻辑(设置微调器/用户输入的动画),然后返回来完成ContinueWith中的逻辑

    public void LoadCustomers()
    {
        // Update UI to show spinner
        this.LoadingCustomers = true;

        this.custService.GetCustomers().ContinueWith((t) =>
        {
            var customers = t.Result;
            // code truncated for clarity

            // Update UI to hide spinner
            this.LoadingCustomers = false;
        });
    }
根据评论中的要求,下面是GetCustomers的代码。dbContext是EntityFrameworkCore

    public async Task<List<CustomerModel>> GetCustomers()
    {
        return await this.dbContext.Customers.ToListAsync();
    }
public异步任务GetCustomers()
{
return wait this.dbContext.Customers.toListSync();
}
更新


然而,FCin的答案是正确的;其根源似乎是EFCore和ToListSync,它不是异步运行的。

编辑:@bradley uffner建议只写以下内容:

public async Task LoadCustomers()
{
    // Update UI to show spinner
    this.LoadingCustomers = true;

    var customers = await this.custService.GetCustomers();
    // code truncated for clarity

    // you are still on UI thread here
    this.LoadingCustomers = false;
}

这个怎么样:

public async Task LoadCustomers()
{
    // Update UI to show spinner
    this.LoadingCustomers = true;

    await Task.Run(async () =>            
    {
        var customers = await this.custService.GetCustomers();
        // code truncated for clarity
    });

    this.LoadingCustomers = false;
}

await
之后的代码在当前线程上执行,因此它应该是现成的。

编写这种方法的正确方法是从头到尾使用
async/await
。现在您正在执行fire,如果任务中出现异常,请忘记其含义。运行,您将永远不会知道它。您应该从事件处理程序开始。这可以是任何东西,鼠标点击,页面加载等

private async void MouseEvent_Click(object sender, EventArgs args)
{
    await LoadCustomers();
}

public async Task LoadCustomers()
{
    // Update UI to show spinner
    this.LoadingCustomers = true;

    // We don't need Device.BeginInvokeOnMainThread, because await automatically 
    // goes back to calling thread when it is finished
    var customers = await this.custService.GetCustomers();

    this.LoadingCustomers = false;
}

有一种简单的方法可以记住何时使用
任务。运行
。使用
Task。仅当您执行CPU限制的操作(例如计算PI的位数)时才运行

如何实现
GetCustomers
?在返回
任务之前,它可能处于阻塞状态。您还可以将
LoadCustomers
设置为
async Task
,从而避免显式使用
ContinueWith
(或者
async void
,如果您需要它作为特定类型的处理程序)什么框架?Asp.net?wpf?winforms?我已经用GetCustomers方法更新了这个问题,它是一个Xamarin Forms项目。如果
GetCustomers
已经是一个
async
支持
任务
,为什么还要麻烦使用
任务。运行
,而不是直接等待它?编译器将自动将
async
方法转换为一系列幕后延续。这正是
async
/
await
的设计初衷。[…]除非
//代码中有某些东西为了清晰起见被截断了
,需要另一个线程。如果只是“正常”代码,我强烈建议直接等待;您根本不必担心跨线程封送。如果
this.custService.GetCustomers()
已经是一个
异步
支持
任务
,为什么要使用
任务运行
,我甚至没有检查代码的内容,而是直接等待它:D让我来解决这个问题。您需要将异步添加到事件处理程序签名中。