使用 async/await 的技巧

Ale*_*lex 2 c# unity-game-engine async-await uwp hololens

最近几天我一直在阅读C# 异步编程。原因是 UWP 中的文件选择器(这是必要的,因为我正在 Unity 中为 Hololens 2 编程)。尽管有很多来源,即123,但我对正确使用有一些理解问题,也许这里有经验的用户可以给我一些提示。

我正在尝试做的一个例子:

程序开始:

public class SceneUIHandler : MonoBehaviour
{
  openFile()
  {
    pickFile(); // calls await filepicker.PickSingleFileAsync();
    loadData(path); // calls FileLoader.loadFile with path from filepicker for the reader
    showData(); // should display the data
  }
}
Run Code Online (Sandbox Code Playgroud)

装载机:

public class FileLoader:
    {
      async void loadFile(string path)
      {
        Task<StreamReader> streamReaderTask = getStreamReader(filePath);
        StreamReader sr = await streamReaderTask;
        // after that read file with the StreamReader...
        ...
      }

      async Task<StreamReader> getStreamReader(string path)
      {
       StorageFile file = await StorageFile.GetFileFromPathAsync(path);
       var randomAccessStream = await file.OpenReadAsync();
       Stream stream = randomAccessStream.AsStreamForRead();
       StreamReader str = new StreamReader(stream);

       return str;
      }
    }
Run Code Online (Sandbox Code Playgroud)

因此,我使用文件选择器获取路径,然后在 FileLoader 类中使用该路径调用该文件并创建一个流读取器。到目前为止一切正常。

我的问题是,如果读取器的创建需要更长的时间,代码会因为等待而停止,并openFile()在方法之后再次相应地跳转到 SceneUIHandler中loadData()。但在那之后,showData()我希望数据已经加载。从教程中,我现在将openFile() 异步编写一个await loadData()此处。如果我这样做,我必须一个接一个地异步一个方法,因为我必须在某个地方等待,直到加载数据,否则我无法显示、更改、与(未加载的)数据交互。但是通过async + wait我等待并继续前面的方法(这也依赖于数据)。

我必须如何或在哪里停止,或者在使用异步时是否必须以不同的方式分离代码,以便代码流的其余部分独立于数据?

我现在还可以Cross thread invocation exception通过创建和调用稍微不同的 getStreamReader(string path) 方法来获得,该方法仅返回 BinaryReader 而不是 StreamReader。

Ste*_*ary 5

我还建议阅读我的异步最佳实践文章。前两个最佳实践仍然是最重要的。

从教程中,我现在将 openFile() 设为异步,以在此处编写等待 loadData() 。

第一个最佳实践是“避免async void”,因为您的代码无法知道该方法何时完成。换句话说,使用async Task而不是async void, 以及await该方法调用。

如果我这样做,我必须一个接一个地异步一个方法,因为我必须在某个地方等待,直到加载数据,否则我无法显示、更改、与(未加载的)数据交互。但是通过 async + wait 我等待并继续前面的方法(这也依赖于数据)。

我必须如何或在哪里停止,或者在使用异步时是否必须以不同的方式分离代码,以便代码流的其余部分独立于数据?

第二个最佳实践是“async一路使用”。一开始觉得这很奇怪很正常,但这是正确的程序。

最终,您将回归到您的框架。对于 UWP/Unity,您将拥有最高级别的 UI。您要做的就是显示某种“正在加载...”屏幕(立即且同步),然后在异步工作完成时更新该屏幕。我有一篇关于异步数据绑定的文章,是从 MVVM/WPF 角度编写的,但相同的想法适用于任何 UI 框架。