asynchronous - UWP/WinRT 与 C++/CX : In a chain of asynchronous tasks, 如何在它们之间传递数据?

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

据我所知,一个 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 时是否可能会相互干扰?
  • 这只是一个只有一个变量的简单示例,但假设我还想跟踪文件的路径、其文件属性以及许多其他特征。现在,随着类变量数量的增加,类看起来越来越难看。

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

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

最佳答案

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

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);
});

关于asynchronous - UWP/WinRT 与 C++/CX : In a chain of asynchronous tasks, 如何在它们之间传递数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31897075/

相关文章:

c# - 与异步方法相关的 VoidTaskResult 类型是什么?

java - 轻松声明交叉类型的 java lambda

c# - WinRT 中的集合导航

xaml - 如何检测方向变化并更改布局?

c# - NetworkStream ReadAsync取消

Javascript async parallel - 如何返回最终结果/回调?

java - Scala lambdas 实现与 Java 8

python - 生成 lambda 函数组合的组合

c# - 如何调用不在.NET中开发的Web服务

c# - 为什么我需要使此方法异步?