当我需要等待事件时如何使方法异步
Posted
技术标签:
【中文标题】当我需要等待事件时如何使方法异步【英文标题】:How to make a method asynchronous when I need to wait for an event 【发布时间】:2017-07-27 10:39:20 【问题描述】:我做了一个这样的函数:
public void GetData(string dataToPost)
var url = "some URL";
using (var client = new WebClient())
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.UploadStringCompleted += (s, e) =>
Console.WriteLine("Result is here");
Console.WriteLine(e.Result);
;
client.UploadStringAsync(new System.Uri(url), "POST", dataToPost);
这里的问题是我想要从服务器返回一个值(HTTP 响应)。
我希望我的函数是异步的,因此例如我希望能够在一个循环中调用它 5 次,而无需等待每次调用在下一次调用之前返回某些内容。
我不知道如何实现它。我试图创建一些 Task 对象来等待它,但是 Task 需要一个委托,我不知道我可以给它什么委托。
上面的 Te 函数使用了一个事件,该事件在结果到来时被触发 - 所以我需要返回该结果。
我该怎么做?
【问题讨论】:
这是一个控制台应用程序。我对这一切都很陌生,所以我不确定我是否理解你的意思。 UploadStringAsync 返回无效。 //edit 好像有人删了他的评论 对不起,我以为你在使用HttpClient
。您需要订阅UploadStringCompleted
事件,该事件将在调用完成后被调用。
是否可以切换到HttpClient
,因为它具有原生异步/等待支持,例如msdn.microsoft.com/en-us/library/hh138242.aspx。
@Igor,我没关系,如果你知道用HttpClient做的方法,我可以用它
在这种情况下,请参阅上一个问题/答案:***.com/a/15176685/1260204
【参考方案1】:
WebClient
有一个返回 Task<string>
的重载:
https://msdn.microsoft.com/en-us/library/hh193920(v=vs.110).aspx
您可以触发所有请求,然后使用Task.WhenAll
等待它们:
public void GetData(string dataToPost)
var url = "some URL";
var url2 = "some other URL";
using (var client = new WebClient())
client.Headers[HttpRequestHeader.ContentType] = "application/json";
var task1 = client.UploadStringTaskAsync(new System.Uri(url), "POST", dataToPost);
var task2 = client.UploadStringTaskAsync(new System.Uri(url2), "POST", dataToPost);
var results = Task.WhenAll(task1, task2).Result;
foreach (var result in results)
Console.WriteLine("Result is here");
Console.WriteLine(result);
如果您可以将 GetData 更改为 async
方法,那就更好了,您可以在 Task.WhenAll
上使用 await
【讨论】:
【参考方案2】:正如在 cmets 中已经说过的,HttpClient
是此类任务更自然的选择。但是,您仍然可能想知道如何提供订阅事件的任务,这可以通过 TaskCompletionSource<T>
完成,只需对您的代码进行非常小的更改:
private Task<string> GetData(string dataToPost)
var url = "some URL";
var resultSource = new TaskCompletionSource<string>();
using (var client = new WebClient())
client.Headers[HttpRequestHeader.ContentType] = "application/json";
client.UploadStringCompleted += (s, e) =>
Console.WriteLine("Result is here");
Console.WriteLine(e.Result);
// this will complete the task
resultSource.SetResult(e.Result);
;
client.UploadStringAsync(new System.Uri(url), "POST", dataToPost);
return resultSource.Task;
在这种情况下,您还可以设置cancellation(也可以使用given token)和exception(即使使用multiple exceptions),这样它自然会满足您的需求。对于并发事件订阅的情况,这三种方法都可以Try*
方式完成。
还要注意@Stefanod'Antonio' 对async
method 过载的回答。
【讨论】:
感谢您的意见,这很有趣。在我看来,这就像 javascript 的承诺。 C# 中的Task
和 Javascript 中的 Promise
几乎是等价的。以上是关于当我需要等待事件时如何使方法异步的主要内容,如果未能解决你的问题,请参考以下文章