C# 在基于事件的异步模式上使用任务并行库
我正在写一个网络应用程序 消息通过以下传输方式发送:C# 在基于事件的异步模式上使用任务并行库,c#,asynchronous,task-parallel-library,event-based-programming,C#,Asynchronous,Task Parallel Library,Event Based Programming,我正在写一个网络应用程序 消息通过以下传输方式发送: Network.SendMessage (new FirstMessage() ); 我可以注册一个事件处理程序,在该消息类型到达时调用,如下所示: Network.RegisterMessageHandler<FirstMessage> (OnFirstMessageReceived); public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs
Network.SendMessage (new FirstMessage() );
我可以注册一个事件处理程序,在该消息类型到达时调用,如下所示:
Network.RegisterMessageHandler<FirstMessage> (OnFirstMessageReceived);
public void OnFirstMessageReceived(EventArgs<FirstMessageEventArgs> e)
{
Network.SendMessage( new SecondMessage() );
}
public void OnSecondMessageReceived(EventArgs<SecondMessageEventArgs> e)
{
Network.SendMessage( new ThirdMessage() );
}
public void OnThirdMessageReceived(EventArgs<ThirdMessageEventArgs> e)
{
Network.SendMessage( new FourthMessage() );
}
public void OnFourthMessageReceived(EventArgs<FourthMessageEventArgs> e)
{
// Authentication is complete
}
public void Drink() {}
public void Eat() {}
public void Sleep() {}
Task.Factory.StartNew( () => Drink() )
.ContinueWith( () => Eat() )
.ContinueWith( () => Sleep() );
这与我的基于事件的异步模式相反,在这种模式中,只有在接收到消息时才调用每个事件处理程序方法
换句话说,我不能做这样的事情(但我想):
我读过,但不太明白。似乎我需要的是
TaskCompletionSource
。如果我想从基于事件的异步模式(如上面的代码块)创建一个任务,它会是什么样子?Jeremy Likness有一个博客标题,您可能会感兴趣。以下是他试图回答的问题:
这个概念很简单:我们经常希望一组异步操作按顺序执行。也许您必须从服务加载列表,然后加载所选项目,然后触发动画。这可以通过链接已完成的事件或嵌套lambda表达式来实现,但是有更干净的方法吗
关于TaskCompletionSource,您是对的,它是将EAP(基于事件的异步模式)转换为TPL任务的关键 这里记录了这一点: 以下是简化代码:
public static class Extensions
{
public static Task<XDocument> GetRssDownloadTask(
this WebClient client, Uri rssFeedUri)
{
// task completion source is an object, which has some state.
// it gives out the task, which completes, when state turns "completed"
// or else it could be canceled or throw an exception
var tcs = new TaskCompletionSource<XDocument>();
// now we subscribe to completed event. depending on event result
// we set TaskCompletionSource state completed, canceled, or error
client.DownloadStringCompleted += (sender, e) =>
{
if(e.Cancelled)
{
tcs.SetCanceled();
}
else if(null != e.Error)
{
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(XDocument.Parse(e.Result));
}
};
// now we start asyncronous operation
client.DownloadStringAsync(rssFeedUri);
// and return the underlying task immediately
return tcs.Task;
}
}
非常有趣。这肯定是有用的。我将看到其他答案,特别是那些使用任务并行库的答案。这是一个很好的技巧,让我能够更轻松地使用WebClient。谢谢
Task.Factory.StartNew( () => OnFirstMessageReceived() )
.ContinueWith( () => OnSecondMessageReceived() )
.ContinueWith( () => OnThirdMessageReceived() )
.ContinueWith( () => OnFourthMessageReceived() );
public static class Extensions
{
public static Task<XDocument> GetRssDownloadTask(
this WebClient client, Uri rssFeedUri)
{
// task completion source is an object, which has some state.
// it gives out the task, which completes, when state turns "completed"
// or else it could be canceled or throw an exception
var tcs = new TaskCompletionSource<XDocument>();
// now we subscribe to completed event. depending on event result
// we set TaskCompletionSource state completed, canceled, or error
client.DownloadStringCompleted += (sender, e) =>
{
if(e.Cancelled)
{
tcs.SetCanceled();
}
else if(null != e.Error)
{
tcs.SetException(e.Error);
}
else
{
tcs.SetResult(XDocument.Parse(e.Result));
}
};
// now we start asyncronous operation
client.DownloadStringAsync(rssFeedUri);
// and return the underlying task immediately
return tcs.Task;
}
}
public static void Main()
{
var client = new WebClient();
client.GetRssDownloadTask(
new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx"))
.ContinueWith( t => {
ShowXmlInMyUI(t.Result); // show first result somewhere
// start a new task here if you want a chain sequence
});
// or start it here if you want to get some rss feeds simultaneously
// if we had await now, we would add
// async keyword to Main method defenition and then
XDocument feedEric = await client.GetRssDownloadTask(
new Uri("http://blogs.msdn.com/b/ericlippert/rss.aspx"));
XDocument feedJon = await client.GetRssDownloadTask(
new Uri("http://feeds.feedburner.com/JonSkeetCodingBlog?format=xml"));
// it's chaining - one task starts executing after
// another, but it is still asynchronous
}