Hos*_*Rad 15 .net c# asynchronous async-await taskcompletionsource
我想用来TaskCompletionSource
包装MyService
哪个是简单的服务:
public static Task<string> ProcessAsync(MyService service, int parameter)
{
var tcs = new TaskCompletionSource<string>();
//Every time ProccessAsync is called this assigns to Completed!
service.Completed += (sender, e)=>{ tcs.SetResult(e.Result); };
service.RunAsync(parameter);
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
这段代码第一次运行良好.但是我第二次ProcessAsync
简单地Completed
再次调用事件处理程序(service
每次使用相同的变量),因此它将执行两次!并且它第二次抛出此异常:
在已经完成时尝试转换任务最终状态
我不确定,我应该tcs
像这样声明一个类级变量:
TaskCompletionSource<string> tcs;
public static Task<string> ProccessAsync(MyService service, int parameter)
{
tcs = new TaskCompletionSource<string>();
service.Completed -= completedHandler;
service.Completed += completedHandler;
return tcs.Task;
}
private void completedHandler(object sender, CustomEventArg e)
{
tcs.SetResult(e.Result);
}
Run Code Online (Sandbox Code Playgroud)
我必须使用不同的返回类型包装许多方法,这样我必须编写丢失的代码,变量,事件处理程序,所以我不确定这是否是这种情况下的最佳实践.那么有更好的方法来完成这项工作吗?
i3a*_*non 26
这里的问题是Completed
每个动作都会引发事件,但TaskCompletionSource
只能完成一次.
你仍然可以使用本地TaskCompletionSource
(你应该).您只需要在完成之前取消注册回调TaskCompletionSource
.这样,具有此特定功能的特定回调TaskCompletionSource
将永远不会再次调用:
public static Task<string> ProcessAsync(MyService service, int parameter)
{
var tcs = new TaskCompletionSource<string>();
EventHandler<CustomEventArg> callback = null;
callback = (sender, e) =>
{
service.Completed -= callback;
tcs.SetResult(e.Result);
};
service.Completed += callback;
service.RunAsync(parameter);
return tcs.Task;
}
Run Code Online (Sandbox Code Playgroud)
这也将解决当您的服务保持对所有这些委托的引用时可能发生的内存泄漏.
您应该记住,虽然您不能同时运行多个这些操作.除非您有办法匹配请求和响应,否则至少不会.
看来会多次MyService
引发该事件。Completed
这会导致SetResult
被多次调用,从而导致您的错误。
我看到你有 3 个选择。将 Completed 事件更改为仅引发一次(似乎很奇怪,您可以完成多次),更改SetResult
为TrySetResult
这样,当您尝试第二次设置它时,它不会引发异常(这确实会引入一个小的内存泄漏,因为事件仍然被调用并且完成源仍然尝试设置),或者取消订阅事件(i3arnon 的答案)
归档时间: |
|
查看次数: |
10525 次 |
最近记录: |