Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wrap 3rdParty function with callback to be able to wait for the callback finish and then return a result from callback function?

I want to wrap 3rd party function to Task to be able to await for finish the callback function. This is what I would like to achieve:

public MyClass MyProperty { 
    get
    {
        if (myProperty == null)
            myProperty = LoadMyValue("1234");
        return myProperty ;
    }
    set
    {
        myProperty = value;
    }
}

public MyClass LoadMyValue(string id) {
        return MyClassTools.LoadMyValue(id);
}

and in MyClassTools

static public MyClass LoadMyValue(string id) {
    3rdPartyApi.Call(id, Callback);
    // here I want to return Callback result
}

static MyClass Callback(3rdPartyResult result) {
    return new MyClass(result); 
}

How to use here Tasks and async/await to be able return Callback result directly from function LoadMyValue?

like image 281
bendi Avatar asked Nov 22 '25 12:11

bendi


1 Answers

As Noseratio suggested, you can use TaskCompletionSource<T> to wrap the asynchronous API:

public static Task<3rdPartyResult> CallAsync(string id)
{
  var tcs = new TaskCompletionSource<3rdPartyResult>();
  3rdPartyApi.Call(id, result =>
  {
    if (result.Exception == null) // or whatever
      tcs.TrySetResult(result);
    else
      tcs.TrySetException(result.Exception);
  });
  return tcs.Task;
}

You can then make LoadMyValue an asynchronous method:

static public async Task<MyClass> LoadMyValueAsync(string id)
{
  return new MyClass(await CallAsync(id));
}

However, this will not help you return the value from your property. Properties cannot be asynchronous. In your case, it looks like you want an "asynchronous lazy" type of value, which you can do like this:

private readonly Lazy<Task<MyClass>> myProperty =
    new Lazy<Task<MyClass>>(() => LoadMyValueAsync("1234");
public Lazy<Task<MyClass>> MyProperty
{
  get { return myProperty; }
}

Note that I removed the setter since the semantics don't make sense for an asynchronously lazy-evaluated property.

You can then use the property like this:

MyClass value = await MyProperty.Value;

There are some types out there that can make the code slightly easier. E.g., Noseratio's type for callback wrapping, or Stephen Toub's AsyncLazy<T> (which is also a part of my AsyncEx library).

like image 187
Stephen Cleary Avatar answered Nov 24 '25 05:11

Stephen Cleary



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!