Comment attendons-nous la fonction déléguée asynchrone C # en C ++ / CX?

Il s’agit de la communication entre le C++ (code partagé de différentes plates-formes) avec C# (Windows Universal App). Nous soaps que ce qui suit est un appel de fonction de C++ à C# .

C #

 class FooCS { FooCS() { FooC c = new ref FooC(); c.m_GetSomeValueEvent = GetSomeValueEvent; // Some other stuff ... } ssortingng GetSomeValueEvent() { // Some other stuff ... return "Hello World"; } } 

C ++

 public delegate Platform::Ssortingng GetSomeValueEventHandler(); class FooC { public: event GetSomeValueEventHandler^ m_GetSomeValueEvent; void someFunction(){ Platform::Ssortingng^ str = m_GetSomeValueEvent(); // Some other stuff ... } } 

Ce qui précède est très simple. Mais le problème est que cette chaîne GetSomeValueEvent() en C# effectue des tâches lourdes telles que la lecture des données de la firebase database et que je dois le rendre async .

  async Task GetSomeValueEvent() { // Some other stuff ... return "Hello World"; } 

Maintenant, voici la question: Comment puis-je faire attendre mon code C++ pour le retour de cette fonction de délégué? En d’autres termes, à quoi devrait être modifiée la signature suivante?

  public delegate Platform::Ssortingng GetSomeValueEventHandler(); 

J’ai été googler autour et ne peut pas trouver la bonne terminologie pour ce problème. Si vous savez avec certitude que c’est impossible, il serait au moins agréable de le savoir.


C’est finalement ce que nous faisons:

  ssortingng GetSomeValueEvent() { // Convert a async method to non-async one var val = someAsyncMethod().Result; // Some other stuff ... return "Hello World"; } 

Vous devez vous assurer que GetSomeValueEvent ne s’exécute pas sur le thread principal pour éviter les interblocages.

UPD : Retourner une valeur d’un événement est une très mauvaise idée. Considérez les autres options comme une sorte de modèle observable mais avec un seul observateur.

Comme @RaymondChen l’a mentionné, pour les événements asynchrones, il est préférable d’utiliser le modèle de report. C’est un modèle couramment utilisé dans Windows Runtime.

Ajoutez la méthode GetDeferral() à vos GetDeferral() d’événement qui renvoie un object de report spécial. Cet object doit avoir la méthode Complete() qui informe votre code qu’une opération asynchrone est terminée.

================================================== =========================

Le mot clé async ne modifie en fait pas un prototype de fonction. Il vous suffit donc de modifier la valeur de retour dans votre délégué pour qu’elle corresponde à celle d’origine ( Task ).

Mais il y a un inconvénient: Windows Runtime n’a pas le type Task<> , il fait partie de TPL qui est une bibliothèque .NET. Au lieu de cela, Windows Runtime utilise IAsyncOperation<> et IAsyncAction pour représenter des opérations asynchrones.

Alors, voici ce que vous devez faire:

  1. Modifier la signature du délégué:

     public delegate Windows::Foundation::IAsyncOperation GetSomeValueEventHandler(); 
  2. Utilisez la méthode d’extension AsAsyncOperation() pour convertir la Task<> en IAsyncOperation<> :

     async Task GetSomeValueEvent() { // Some other stuff ... return "Hello World"; } IAsyncOperation GetSomeValueEventWrapper() { return GetSomeValueEvent().AsAsyncOperation(); } FooCS() { FooC c = new ref FooC(); c.m_GetSomeValueEvent = GetSomeValueEventWrapper; // Some other stuff ... } 

Ce que je ferais, c’est d’utiliser un équivalent c ++ de:

  var result = GetSomeValueEvent().GetAwaiter().GetResult(); 

Ce que cela va faire pour vous, ce n’est pas seulement récupérer le résultat, mais aussi passer toutes les exceptions qui se produisent dans cette tâche.