AsyncEnumerator对EAP的支持
去年在异步编程中开始使用Wintellect's .NET Power Threading Library中的AsyncEnumerator,这个库通过将程序员较陌生的异步编程模型转化为程序员较熟悉的同步编程模型来实现异步操作,较大的改善了异步代码的易写、易读、易维护性。
目前对AsyncEnumerator介绍的文章已经比较多了,但集中于APM(Asynchronous Programming Model)模式中的应用,而.NET中,特别是Silverlight中还有很多对象是使用EAP(Event-based Asynchronous Pattern),对应的EAP与AsyncEnumerator结合的文章与例子很少,加上Jeffrey Richter不喜欢EAP模型,让我一度以为AsyncEnumerator不支持,于是自己去实现了EAP和AsyncEnumerator的结合。后来项目后期对代码重构时,有时间就再仔细看了看Power Threading的实现,发现其本身对EAP的支持是有封装的。下面是基于AsyncEnumerator使用Silverlight进行Socket通信的例子(Silverlight的Socket只有EAP模型):
SocketAsyncEventArgs socketEventArg = new SocketAsyncEventArgs();
socketEventArg.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Tcp;
DnsEndPoint host = new DnsEndPoint(HtmlPage.Document.DocumentUri.Host, Configurations.PORT);
socketEventArg.RemoteEndPoint = host;
AsyncEnumerator asyncEnum = new AsyncEnumerator();
EventApmFactory<SocketAsyncEventArgs> eventApmFactory
= new EventApmFactory<SocketAsyncEventArgs>();
//异步代码组织在GetEnumerator()中
//IEnumerator<int> GetEnumerator(SocketAsyncEventArgs e,AsyncEnumerator ae){...}
var enumerator = GetEnumerator(socketEventArg,asyncEnum);
EventHandler<SocketAsyncEventArgs> eventHandler =
eventApmFactory.PrepareOperation(asyncEnum.End()).EventHandler;
socketEventArg.Completed += eventHandler;
asyncEnum.BeginExecute(enumerator, asyncEnum.EndExecute);
socketEventArg.SocketClientAccessPolicyProtocol = SocketClientAccessPolicyProtocol.Tcp;
DnsEndPoint host = new DnsEndPoint(HtmlPage.Document.DocumentUri.Host, Configurations.PORT);
socketEventArg.RemoteEndPoint = host;
AsyncEnumerator asyncEnum = new AsyncEnumerator();
EventApmFactory<SocketAsyncEventArgs> eventApmFactory
= new EventApmFactory<SocketAsyncEventArgs>();
//异步代码组织在GetEnumerator()中
//IEnumerator<int> GetEnumerator(SocketAsyncEventArgs e,AsyncEnumerator ae){...}
var enumerator = GetEnumerator(socketEventArg,asyncEnum);
EventHandler<SocketAsyncEventArgs> eventHandler =
eventApmFactory.PrepareOperation(asyncEnum.End()).EventHandler;
socketEventArg.Completed += eventHandler;
asyncEnum.BeginExecute(enumerator, asyncEnum.EndExecute);
其中关键的代码是:
// 用EventApmFactory来创建一个Handler,这个Handler在每次事件触发时
// 调用asyncEnum.End(),将执行控制交还Enumerator,
// Enumerator接着上次yield return之后的地方执行
EventHandler<SocketAsyncEventArgs> eventHandler =
eventApmFactory.PrepareOperation(asyncEnum.End()).EventHandler;
socketEventArg.Completed += eventHandler;
// 调用asyncEnum.End(),将执行控制交还Enumerator,
// Enumerator接着上次yield return之后的地方执行
EventHandler<SocketAsyncEventArgs> eventHandler =
eventApmFactory.PrepareOperation(asyncEnum.End()).EventHandler;
socketEventArg.Completed += eventHandler;
这个代码比我自己的EAP封装代码要简化很多,此外,Jeffrey在BLog中对Task与AsyncEnumerator的结合做了说明:
private static IEnumerator<Int32> AsyncEnumeratorAndTasks(AsyncEnumerator ae) {
var t = new Task<DateTime>(() => { Thread.Sleep(10000); return DateTime.Now; });
t.Start();
// The Task tells the AsyncEnumerator when it is done
// If you don’t need to identify the Task, you can pass ‘null’ instead of ‘task’
t.ContinueWith(task => ae.End()(task));
yield return 1; // Waits for the 1 Task to complete
// You MUST call DequeueAsyncResult to Remove the entry form the AsyncEnumerator object’s collection
// Casting the return value and assigning to ‘t’ is not necessary; since ‘t’ already refer to the same Task object
t = (Task<DateTime>) ae.DequeueAsyncResult();
Console.WriteLine(t.Result); // Shows the DateTime when the Task completed
}
var t = new Task<DateTime>(() => { Thread.Sleep(10000); return DateTime.Now; });
t.Start();
// The Task tells the AsyncEnumerator when it is done
// If you don’t need to identify the Task, you can pass ‘null’ instead of ‘task’
t.ContinueWith(task => ae.End()(task));
yield return 1; // Waits for the 1 Task to complete
// You MUST call DequeueAsyncResult to Remove the entry form the AsyncEnumerator object’s collection
// Casting the return value and assigning to ‘t’ is not necessary; since ‘t’ already refer to the same Task object
t = (Task<DateTime>) ae.DequeueAsyncResult();
Console.WriteLine(t.Result); // Shows the DateTime when the Task completed
}
分类:
.net 2.0
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix