使同步代码依赖于异步代码

本文关键字:代码 异步 依赖于 同步 | 更新日期: 2023-09-27 18:29:12

在我当前的项目中,我将某些对象的状态存储在XML文件中。当我在一个WPF项目中工作时,我需要使用异步方法来完成这项工作。

正因为如此,我在加载应用程序时遇到了一个问题。我要从XML文件中重新创建这些对象的状态,这必须异步完成,但我的内容取决于这些对象的状况,在我的情况下,这导致在使用它们之前,这些对象还没有完全实例化。

简而言之:我的同步方法取决于我的异步方法在启动应用程序时实例化了我的对象。

下面是一些代码,展示了我如何读取整个文件夹的xml文件并生成对象列表。

public List<Restaurant> restaurant = new List<Restaurant>();
public async void ReadRestaurantAsync()
{
    IStorageFolder filesFolder = await Windows.ApplicationModel.Package.Current.InstalledLocation.GetFolderAsync("folder");
    var storageFiles = await filesFolder.GetFilesAsync();
    foreach (var storageFile in storageFiles)
    {
        using (IRandomAccessStream stream = await storageFile.OpenAsync(FileAccessMode.Read))
        using (Stream inputStream = stream.AsStreamForRead())
        {
            DataContractSerializer serializer = new DataContractSerializer(typeof (Restaurant));
            Restaurant objectRead = serializer.ReadObject(inputStream) as Restaurant;
            restaurant.Add(objectRead);
        }
    }
} 

现在,当我从MainPage调用这个异步方法时,我无法处理对象Restaurant,因为它还没有完全实例化。

我想在尝试与Restaurant交互之前,我必须等待方法完全执行,但这似乎也有点奇怪,因为它破坏了异步方法的整个想法。

使同步代码依赖于异步代码

好吧,您希望await异步代码,而不是直接等待。这将使GUI在加载数据时保持响应(可能还会显示加载消息,具体取决于加载所需的时间)。

同步方法调用异步方法和等待是没有意义的。如果你这样做,你可以首先使用同步方法,这样可以节省开销。您希望一直是异步的(是的,这确实意味着您不想在构造函数中加载数据,但无论如何都不应该这样做)。

请注意,您可以在WinForms/WPF事件处理程序中使用await,所以可以使用这些LoadDataBinding事件等。

简而言之:当你发现自己有同步代码在等待异步代码时,你的设计很可能有缺陷。在任何情况下,它都表明您忽略了同步问题等,当您开始使用await时,这些问题不会神奇地消失——访问全局变量仍然是一个非常糟糕的主意。相反,您希望任务返回一个值(在您的情况下,是Restaurant的可枚举值),并将这些值添加到UI线程中的全局列表中(即,在发布回同步上下文的continuation上)。现在,您实际上是在做,因为您正在处理UI线程上的所有异步回调,但这可能是不必要的,而且实际上可能是一个愚蠢的开销,使加载需要更长的时间。

想想async。不要中途停下来。