我有一个 API,其界面如下所示:
void SendRequest(Guid id, IRequest request);
event EventHandler<ResponseEventArgs> ResponseReceived;
实现此方法的最佳方式是什么?
Task<T> GetResponse(IRequest request) where T: IRequest
请注意,多个请求可能会相互重叠,因此当响应返回时,我需要查找父请求。我有一种感觉 TaskCompletionSource 可能有用,但不能完全拼凑起来。
最佳答案
编辑:
如果您想在不阻塞线程的情况下执行此操作,您可以使用 TaskCompletionSource<T>
执行类似的操作:
var completionSource = new TaskCompletionSource<T>();
var requestIdentifier = Guid.NewGuid();
EventHandler<ResponseEventArgs> handler = null;
handler = (sender, args) =>
{
if(args.RequestIdentifier == requestIdentifier)
{
api.ResponseReceived -= handler;
// TrySetResult avoids re-entrancy problems in case of an
// API that sends duplicates, but there other ways of
// dealing with this too.
completionSource.TrySetResult((T)args.Response);
}
};
api.ResponseReceived += handler;
// Make this async if you want.
api.SendRequest(requestIdentifier, request);
return completionSource.Task;
原始答案:
我想你想要类似下面的东西,它使用 ManualResetEvent
阻塞线程,直到 API 引发事件:
return Task.Factory.StartNew<T>(() =>
{
var waitHandle = new ManualResetEvent(false);
T result = default(T);
var requestIdentifier = Guid.NewGuid();
EventHandler<ResponseEventArgs> handler = (sender, args) =>
{
if(args.RequestIdentifier == requestIdentifier)
{
result = (T)args.Response; // Not sure how this looks in your API
waitHandle.Set(); // Unblock the thread running the task
}
};
// Attach handler to respond to the response being received.
api.ResponseReceived += handler;
// Send request off.
api.SendRequest(requestIdentifier, request);
// Wait until response is received.
waitHandle.WaitOne();
// Detach handler to prevent leak.
api.ResponseReceived -= handler;
return result;
});
要获得更简洁的方法,请查看 Reactive Extensions .
关于.net - 为远程调用实现 Task<T> 而不是在事件中响应?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11438832/