C# "(沙马林)";异步无效“;框架内覆盖

C# "(沙马林)";异步无效“;框架内覆盖,c#,asynchronous,xamarin,async-await,C#,Asynchronous,Xamarin,Async Await,我有一个从远程服务器检索信息并向用户显示该信息的屏幕。我希望在屏幕显示时更新此信息(不需要额外的用户交互) 这可以接受吗?我已经看到了所有关于“async void”弊病的讨论,以及如何只在事件处理程序中使用它,而这并不是一个很好的事件处理程序 由于我(1)在获取所有异步之前调用了base.OnAppearing(),以及(2)捕获了我的异常,所以在这种情况下,框架是否保证是正常的 protected override OnAppearing(){ base.OnAppearing();

我有一个从远程服务器检索信息并向用户显示该信息的屏幕。我希望在屏幕显示时更新此信息(不需要额外的用户交互)

这可以接受吗?我已经看到了所有关于“async void”弊病的讨论,以及如何只在事件处理程序中使用它,而这并不是一个很好的事件处理程序

由于我(1)在获取所有异步之前调用了base.OnAppearing(),以及(2)捕获了我的异常,所以在这种情况下,框架是否保证是正常的

protected override OnAppearing(){
    base.OnAppearing();

    Task.Run(async()=>{
        try
        {
            // Use VM and Binding... 
            MyVM.Data = (await GoGetTheData ()).Stuff;
        }
        catch (Exception e)
        {

            // Here I think you should use Device.BeginInvokeOnMainThread();
            MyVm.Data = "Narg";
        }
    });
}
在某处

MyText.BindingContext = MyVm;
MyText.SetBinding(Label.TextProperty, "Data");

在处理事件的情况下(在外观上,基本上是显示的回调),这是完全正常的。

返回类型异步方法应返回任务、任务或 空虚

如果该方法不返回任何其他值,请指定任务返回类型 价值观

如果方法需要返回值,请指定任务,其中 TResult是返回的类型(例如int)

void返回类型主要用于需要 信息技术调用void返回异步方法的代码不能等待 结果呢

在短时间内尽可能使用任务,但在与事件处理程序相关的情况下只使用void。

如果您需要调用async,那么您可以根据这个问题使用
TaskCompletionSource

private TaskCompletionSource继续选中;
专用异步无效按钮\u单击\u 1(对象发送方,路由目标)
{
//注意:您可能希望在“进行中”时禁用此按钮,以便
//用户不能单击它两次。
等待GetResults();
//在这里重新启用按钮,可能在finally块中。
}
私有异步任务GetResults()
{ 
//做很多需要很长时间的复杂事情
//(例如,联系一些web服务)
//等待用户单击“继续”。
continueClicked=新建TaskCompletionSource();
按钮continue.Visibility=可见性.Visibility;
等待继续完成任务;
buttonContinue.Visibility=可见性.已折叠;
//更多的工作。。。
}
私有无效按钮继续单击(对象发送者,路由目标)
{
if(continueClicked!=null)
continueClicked.TrySetResult(null);
}
工具书类


假设这是对调用页面显示事件的受保护方法的重写,则这是可以的

此方法实际上是一个事件,它是在引发事件之前调用的方法

编辑:正如@apineda在评论中指出的,下面的情况实际上并非如此


只需注意,异步工作将在任何事件处理程序运行后完成,因为这些事件处理程序是在
base.OnAppearing()中调用的,这是可以接受的。添加这些框架覆盖上的异步支持是有原因的。“async void”通常有一些缺点,但这种情况不适用

但是需要注意的是,您应该确保您的
OnAppearing(Forms)
OnCreate(Android)
ViewDidLoad(iOS)
方法尽快返回,以便您的用户有一个愉快的体验


事实上,您将在许多表单示例中看到这种确切的语法:

此方法如何调用?可以接受,因为这些重写与事件处理程序没有太大区别:它们的存在是为了通知派生类的实例某些事件。但是,您应该跟踪挂起的任务,如
GoGetTheData
。如果在上一个任务完成之前再次调用出现的
on
,该怎么办?如果您愿意,可以将其视为异步重新进入。我更新了代码,表明这是对最初在Xamarin.Forms.Page中定义的“OnAppearing()”的重写。我知道在人们回答后更新代码通常是不好的,但我相信在这种情况下,我更新的代码不会使任何答案或其他讨论无效。这将引发跨线程异常,因为您无法从后台线程访问UI对象…而且,就使用它的后果而言,它与异步void方法几乎相同。最好的选择是使用“绑定”。他还可以尝试使用Device.beginInvokeMainThread();但我认为用户界面可能会冻结用户界面在任何情况下都不会冻结。Task.Run不用于已经异步的方法。它用于将CPU绑定的工作推送到后台线程,以避免冻结主线程。他在问题中表示,他知道它主要用于事件处理程序。你基本上是在重复他所说的,他已经知道了。这是一个非常详细的回答,但他只是问他的具体用途是否可以接受。他展示的方法似乎是调用
页面
显示
事件的方法,因此本质上是一个事件本身。这意味着在这里使用async void应该是可以的。我在第一次修订中说过“在可能的情况下,简短地使用task,但在与事件处理程序相关的情况下,只使用void。”仅供参考,OnAppearing是一个事件回调。不幸的是,情况并非如此。OnAppearing只是ContentPage父对象中的一个空虚拟方法。在页面的另一个事件中分别调用出现的事件处理程序和此方法。链接:@apineda谢谢你注意到这一点。我已经编辑了我的答案。
MyText.BindingContext = MyVm;
MyText.SetBinding(Label.TextProperty, "Data");
private TaskCompletionSource<object> continueClicked;

private async void Button_Click_1(object sender, RoutedEventArgs e) 
{
  // Note: You probably want to disable this button while "in progress" so the
  //  user can't click it twice.
  await GetResults();
  // And re-enable the button here, possibly in a finally block.
}

private async Task GetResults()
{ 
  // Do lot of complex stuff that takes a long time
  // (e.g. contact some web services)

  // Wait for the user to click Continue.
  continueClicked = new TaskCompletionSource<object>();
  buttonContinue.Visibility = Visibility.Visible;
  await continueClicked.Task;
  buttonContinue.Visibility = Visibility.Collapsed;

  // More work...
}

private void buttonContinue_Click(object sender, RoutedEventArgs e)
{
  if (continueClicked != null)
    continueClicked.TrySetResult(null);
}