Joe*_*ton 3 c# pinvoke native task-parallel-library async-await
我正在尝试围绕用本机代码编写的第三方库编写ac#wrapper,以便在我们的应用程序中使用,这些应用程序几乎都是用.NET编写的,我正在努力保持对C#模式的忠诚.这个库中的几乎所有调用本质上都是异步的,将所有异步调用包装到Task <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
}
Run Code Online (Sandbox Code Playgroud)
现在,我通过事件订阅提供了我的返回值,但我相信这将是一个更好的方法来返回我的数据:
class WrapperAroundNativeCode
{
public async Task<string> RequestData(string inputData);
}
Run Code Online (Sandbox Code Playgroud)
到目前为止,我一直未能找到适当的方法来实现这一点,而且我正在接触那些在使用Task <T>对象和async/await模式方面比我更有经验的人.
你会用a 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;
}
}
Run Code Online (Sandbox Code Playgroud)
此答案假定不会同时调用此方法.如果有,你需要一些方法来区分不同的电话.许多API提供了一个userData
有效负载,您可以将其设置为每次调用的唯一值,以便您可以区分.
这听起来像你在寻找TaskCompletionSource<T>
.您可以通过创建TaskCompletionSource
,创建实例MyNativeLibrary
和注册回调来包装您的库,该回调设置任务完成源的结果,然后从同一实例请求数据.如果其中任何一个步骤失败,请在任务完成源上设置错误.然后只需将TaskCompletionSource<>.Task
属性的值返回给调用者.
(假设您可以创建单独的实例MyNativeLibrary
- 如果您只能在整个应用程序中创建单个实例,则会变得更加困难.)