如何用回调包装3rdParty函数以便能够等待回调完成然后从回调函数返回结果

时间:2014-04-11 09:11:02

标签: .net callback task async-await

大家好我想把第三方功能包装到Task就可以等待完成回调功能了。这就是我想要实现的目标..

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

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

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

有没有人知道如何在这里使用Tasks和async / await能够直接从函数LoadMyValue返回回调结果?

1 个答案:

答案 0 :(得分:5)

正如Noseratio建议的那样,您可以使用TaskCompletionSource<T>来包装异步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;
}

然后,您可以使LoadMyValue成为异步方法:

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

但是,这不会帮助您从属性中返回值。属性不能是异步的。在你的情况下,看起来你想要一个&#34;异步懒惰&#34;值类型,您可以这样做:

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

请注意,我删除了setter,因为语义对于异步延迟评估的属性没有意义。

然后您可以使用以下属性:

MyClass value = await MyProperty.Value;

有一些类型可以使代码稍微容易一些。例如,Noseratio's type for callback wrapping或Stephen Toub的AsyncLazy<T>(也是我AsyncEx library的一部分)。