4

我需要在我声明的方法中调用 Async 方法。该方法应该返回一个值。我正在尝试将对 Windows 应用商店的调用包装到一个易于使用的类中。我的方法应该是这样的:

bool Purchase(enum_InAppOption optionToPurchase);

enum_InAppOption是一个枚举,包含所有要购买的应用内选项。在某些时候我需要打电话RequestProductPurchaseAsync。此调用的结果确定该方法是否应返回truefalse。我是 c++/cx 的新手(或者至少从现在到上次使用 c++ 之间我有很长的历史),所以也许这比我想的更容易。

create_task看起来像这样:

create_task(CurrentAppSimulator::RequestProductPurchaseAsync(this->_LastProductId, false))

我考虑/尝试的选项:

  1. 返回任务不会抽象商店

  2. 试图调用等待任务。我有例外An invalid parameter was passed to a function that considers invalid parameters fatal.

  3. 尝试使用structured_task_group,但似乎这不允许非 void 返回方法,或者我试图提供错误的解释。编译器返回错误 C2064(谷歌搜索但我不明白要更改什么)

  4. 使用一系列任务和when_all

在页面中间的http://msdn.microsoft.com/en-us/library/dd492427.aspx#when_all上找到以下代码:

array<task<void>, 3> tasks = 
{
    create_task([] { wcout << L"Hello from taskA." << endl; }),
    create_task([] { wcout << L"Hello from taskB." << endl; }),
    create_task([] { wcout << L"Hello from taskC." << endl; })
};

auto joinTask = when_all(begin(tasks), end(tasks));

// Print a message from the joining thread.
wcout << L"Hello from the joining thread." << endl;

// Wait for the tasks to finish.
joinTask.wait();

所以我试着把它翻译成下面的代码:

array<task<Platform::String^>,1> tasks = {
    create_task(CurrentAppSimulator::RequestProductPurchaseAsync(this->_LastProductId, false))
};

即使我包括编译器抛出 C2065('array':未声明的标识符),C2275('Concurrency::task<_ReturnType>':非法使用这种类型作为表达式和一些错误似乎是跟进这两个错误.

总结一下:如何在异步任务完成后让方法返回,这样我就可以根据异步进行的东西返回有意义的结果?

4

2 回答 2

2

如何在异步任务完成后使方法返回,以便我可以根据异步进行的内容返回有意义的结果?

这没有多大意义:如果你想在返回之前等待它完成, “东西”不是异步的。这就是同步的定义。

使用 C++/CX 时,您不能等待 STA 上尚未完成的任务。任何这样做的尝试都将导致抛出异常。如果您要调用Purchase()STA 并且如果它启动异步操作,则您不能等待该操作完成后再返回。

相反,您可以.then在异步操作完成时使用它来执行另一个操作。如果需要在调用线程上执行延续,请确保传递use_current()延续上下文以确保延续在正确的上下文中执行。

于 2012-10-07T06:12:23.040 回答
1

萨沙,

  1. 返回任务会抽象出商店,我认为这将是最合理的决定,因为您不会限制帮助类的用户立即获得结果,而且还允许他们以自己的方式处理结果并且是异步的。
  2. 正如@James 正确提到的那样,您不允许在 UI 线程中等待,那么您将使应用程序无响应,有不同的方法可以避免等待:

    • concurrency::task::then用;创建一个延续
    • 您不能在 UI 线程中等待,但您可以等待 UI 线程上的操作完成,这意味着您可以将在 UI 上运行的任务的未来结果包装在task_completion_event中,然后在另一个(后台)中等待事件线程并处理结果;

      concurrency::task_completion_event<Platform::String^> purchaseCompleted;
      
      create_task(CurrentAppSimulator::RequestProductPurchaseAsync(
          this->_LastProductId, false)).then(
              [purchaseCompleted](concurrency::task<Platform::String^> task)
      {
          try
          {
              purchaseCompleted.set(task.get());
          }
          catch(Platform::Exception^ exception)
          {
              purchaseCompleted.set_exception(exception);
          }
      });
      
      // and somewhere on non-UI thread you can do
      Platform::String^ purchaseResult = create_task(purchaseCompleted).get();
      
    • 更准确地说,您可以使用更多特定于 WinRT 的工具而不是并发运行时来实现前面的技巧,并且;IAsyncOperation<T>::CompletedIAsyncOperation<T>::GetResults

  3. 在这里似乎无关紧要,因为您只有一项真正的任务,那就是购买。
于 2014-09-02T08:56:49.303 回答