【问题标题】:UWP/WinRT with C++/CX: In a chain of asynchronous tasks, how can data be passed between them?UWP/WinRT with C++/CX:在异步任务链中,如何在它们之间传递数据?
【发布时间】:2015-11-01 00:58:10
【问题描述】:

我知道一个 lambda 表达式的返回值被输入到下一个 lambda 表达式的参数中。但是,如果需要传递多条数据,或者程序结构已经设置了一个lambda的返回类型怎么办?

这是我的工作代码,其中两种情况都是打开文件选择器,然后将其内容作为文本读取,同时记住它来自什么文件:

create_task(picker->PickSingleFileAsync())
.then([this](StorageFile^ file) 
    {
        if (file == nullptr) cancel_current_task();
        m_OpenFilename = file->Name;
        return FileIO::ReadTextAsync(file);
    })
.then([this](String^ fileContents)
    {
        //do something with the filename and file contents
    });

请注意,为了完成这项工作,我需要添加一个类变量来存储异步任务之间的文件名。这让我觉得很糟糕,原因有很多:

  • 有一个类变量供内部使用单个方法是很丑的
  • 这是线程安全的吗?如果有人疯狂地打开文件选择器并选择文件,这些异步任务在访问 m_OpenFilename 时是否会相互干扰?
  • 这只是一个带有一个变量的简单示例,但假设我还想跟踪文件的路径、文件属性以及许多其他特征。现在随着类变量数量的增加,这个类看起来越来越难看。

我的第一种方法是在函数范围内设置一个局部变量,并将其传递给每个 lambda 函数,方法是将它们的捕获列表更改为 [this, OpenFilename]。但是,这会失败,因为在 lambda 执行时,C++/CX 的后台内存处理程序已经丢弃了Openfilename,从而在访问它时导致访问冲突。

在我的示例中,如何将文件的元数据传递给ReadTextAsync 的结果,以便我可以同时访问文件及其内容?

【问题讨论】:

    标签: asynchronous lambda windows-runtime c++-cx uwp


    【解决方案1】:

    最简单的方法是继续构建嵌套延续链:

    auto picker = ref new FileOpenPicker();
    picker->FileTypeFilter->Append(L".txt");
    picker->SuggestedStartLocation = PickerLocationId::Desktop;
    auto task = create_task(picker->PickSingleFileAsync()).then(
      [](StorageFile^ file)
    {
      auto name = file->Name;
      auto task = create_task(file->OpenReadAsync()).then(
        [name](IRandomAccessStreamWithContentType^ iras)
      {
        OutputDebugString(name->Data());
      });
    });
    

    如果您不想这样做(无论出于何种原因),另一种选择是使用shared_ptr 来保存该值;在这种情况下,我将在帮助程序file_info 中保留名称和创建日期:

    struct file_info
    {
      Platform::String^ name;
      Windows::Foundation::DateTime created;
    };
    
    auto picker = ref new FileOpenPicker();
    picker->FileTypeFilter->Append(L".txt");
    picker->SuggestedStartLocation = PickerLocationId::Desktop;
    auto info = std::make_shared<file_info>();
    
    auto task = create_task(picker->PickSingleFileAsync()).then(
      [info](StorageFile^ file) 
    {
      info->name = file->Name;
      info->created = file->DateCreated;
      return create_task(file->OpenReadAsync());
    }).then(
      [info](IRandomAccessStreamWithContentType^ iras)
      {
        OutputDebugString(info->name->Data());
        OutputDebugString(L"\n");
        wchar_t datetime[100];
        _i64tow_s(info->created.UniversalTime, datetime, 100, 10);
        OutputDebugString(datetime);
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-08-24
      • 1970-01-01
      • 2013-01-01
      • 2015-12-05
      • 2019-01-28
      • 1970-01-01
      • 1970-01-01
      • 2012-05-21
      相关资源
      最近更新 更多