2013-10-21 35 views
2

我试图写一个围绕在写在我们的应用程序,这几乎完全写在.NET消耗本机代码的第三方库的C#包装,和我想保持忠实于C#模式。几乎在这个库中的所有调用在本质上是异步的,它似乎是适宜的包裹我所有的异步调用到任务<牛逼>对象。下面是本机库是如何构建一个简化的示例:与任务封装本地异步功能<T>

delegate void MyCallback(string outputData); 

class MyNativeLibrary 
{ 
    public int RegisterCallback(MyCallback callback); // returns -1 on error 
    public int RequestData(string inputData);   // returns -1 on error 
} 

现在,我已经通过事件订阅提供我的返回值,但是我相信这将是一个更好的方式来回报我的数据:

class WrapperAroundNativeCode 
{ 
    public async Task<string> RequestData(string inputData); 
} 

到目前为止,我一直在寻找实现这个适当的方式失败,而我在工作<牛逼工作>对象和比我做异步/ AWAIT模式深入到人们有更多的经验。

+3

你怎么知道哪个'RequestData'引起了'MyCallback'要求? – luiscubal

+1

你如何得到异常通知? –

+0

你如何取消注册回调?或者它自动注销自己? – svick

回答

6

这听起来像你正在寻找TaskCompletionSource<T>。你会通过创建一个TaskCompletionSource,创造MyNativeLibrary实例,并注册其设定的任务完成源的结果的回调,然后再从同一实例请求数据包库中。如果其中任一步骤失败,请在任务完成源上设置错误。然后只需将TaskCompletionSource<>.Task属性的值返回给调用者。

(这是假设你可以创建MyNativeLibrary单独实例 - 如果你只能在你的整个应用程序创建一个例如,它得到了很多困难。)

+0

谢谢,完美的工作。我还有一个问题:'Task'具有泛型和非泛型的特征,但我只看到了'TaskCompletionSource'的通用版本。我错过了吗? –

+1

@JoeyHerrington'任务'扩展了'Task',所以有一个从'Task '到'Task'的隐式转换。你可以建立一个'TaskCompletionSource '并使用'SetResult(null);'(或者任何虚拟值而不是'null')。 – luiscubal

+0

是的,这就是我所做的。我只是不知道是否有实际的非泛型类型。 –

8

你会使用这个TaskCompletionSource<TResult>。沿着以下代码行:

class WrapperAroundNativeCode 
{ 
    public async Task<string> RequestData(string inputData) 
    { 
     var completionSource = new TaskCompletionSource<string>(); 
     var result = Native.RegisterCallback(s => completionSource.SetResult(s)); 
     if(result == -1) 
     { 
      completionSource.SetException(new SomeException("Failed to set callback")); 
      return completionSource.Task; 
     } 

     result = Native.RequestData(inputData); 
     if(result == -1) 
      completionSource.SetException(new SomeException("Failed to request data")); 
     return completionSource.Task; 
    } 
} 

此答案假定不会有并发调用此方法。如果有的话你需要一些方法来区分不同的调用。许多API提供一个userData有效载荷,您可以将其设置为每个呼叫的唯一值,以便您可以区分。

+0

看起来像你钉了它!我尝试了这种技术,它似乎工作得很好。感谢您的帮助 –

+0

对不起,我只能标记出一个正确的答案,否则我会将你和Jon Skeet标记为正确。 –