As we expect the C # async delegate function in C ++ / CX

It is about the relationship between C++ (common code across platforms) with C# (Windows Universal App). We know that we are making a function call from C++ to C# .

WITH#

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

C ++

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

The above is very straightforward. But the problem is that this GetSomeValueEvent() in C# performs some heavy tasks, such as reading data from a database, and I have to do this async .

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

Now the question is: how do I return C++ to return this delegate function? In another word, what should be the next signature should be changed to?

  public delegate Platform::String GetSomeValueEventHandler(); 

I work in search engines and cannot find the correct terminology for this problem. If you know for sure that this is impossible, it would be at least nice to know.


In the end , this is what we do:

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

You must ensure that GetSomeValueEvent does not work in the main thread to prevent a deadlock.

+5
source share
2 answers

UPD Returning a value from an event is a REALLY REQUIRED idea. Consider other options, like some kind of observable pattern, but with one observer.

As @RaymondChen noted, for asynchronous events it is better to use a snooze pattern. This is a commonly used pattern in Windows Runtime.

Add the GetDeferral() method to your event arguments that return a special deferral object. This object must have a Complete() method that informs your code about the completion of an asynchronous operation.

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

The async does not actually modify the function prototype. Therefore, you just need to change the return value in your delegate to match the original ( Task<string> ).

But there is a catch: Windows Runtime is not of type Task<> , it is part of TPL, which is a .NET library. Instead, Windows Runtime uses IAsyncOperation<> and IAsyncAction to represent asynchronous operations.

So here is what you need to do:

  • Change Delegate Signature:

     public delegate Windows::Foundation::IAsyncOperation<Platform::String> GetSomeValueEventHandler(); 
  • Use the AsAsyncOperation() extension method to convert Task<> to IAsyncOperation<> :

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

What I would do is use the C ++ equivalent:

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

what will do for you is not only the result of the selection, but also all the exceptions that occur in this task.

0
source

All Articles