实体框架 – 如何改进这个F#代码以使其更加惯用?
发布时间:2020-12-14 03:52:58 所属栏目:Windows 来源:网络整理
导读:我有一个 Windows服务,使用Entity Framework 5从数据库中的队列中读取电子邮件,然后使用System.Net.Mail.SmtpClient将它们发送到SMTP服务器 这是我第一次尝试编写F#应用程序,我来自C#背景.如何更好地改进功能和/或充分利用F#的功能?你能解释一下这些改变的
我有一个
Windows服务,使用Entity Framework 5从数据库中的队列中读取电子邮件,然后使用System.Net.Mail.SmtpClient将它们发送到SMTP服务器
这是我第一次尝试编写F#应用程序,我来自C#背景.如何更好地改进功能和/或充分利用F#的功能?你能解释一下这些改变的优势是什么吗? worker由服务主机构建,在服务启动时调用其工作函数,在服务停止时将ContinueWorking设置为false. namespace EmailService open log4net open System open System.Linq open System.Net.Mail open EmailService.Context type Worker(contextFactory: EmailContextFactory,mailClient: ISmtpClient,logger: ILog) = let MapToMessage(email : Email) = let message = new MailMessage() message.Sender <- new MailAddress(email.From) message.From <- new MailAddress(email.From) message.Subject <- email.Subject message.Body <- email.Body message.IsBodyHtml <- email.IsBodyHtml message.To.Add(email.To) (email,message) member val ContinueWorking = true with get,set member this.Work() = logger.Info "Starting work" let mutable unsentEmails = Array.empty<Email> while this.ContinueWorking do use context = contextFactory.GetEntities() while this.ContinueWorking && Array.isEmpty unsentEmails do System.Threading.Thread.Sleep(1000) unsentEmails <- query { for q in context.QueueItems do where (q.Error = null) select q.Email } |> query.Take(10) |> query.toArray Array.map MapToMessage unsentEmails |> Array.iter (fun (email,message) -> try mailClient.SendMail(message) email.DateSent <- new Nullable<DateTime>(DateTime.UtcNow) context.QueueItems.Remove(email.QueueItem) |> ignore with | ex -> logger.Error(ex) email.QueueItem.Error <- ex.ToString()) context.SaveChanges() |> ignore logger.Info (sprintf "Sent %d emails" unsentEmails.Length) logger.Info "Work complete" 解决方法
Work方法创建一个最终需要停止的长时间运行的进程.在F#中表示这一点的更好方法是使用异步工作流 – 可以暂停异步工作流而不阻塞线程(因此您不需要Thread.Sleep)并且可以使用CancellationToken轻松取消它.
否则,您的代码对我来说很好.我做了一些小的改动(比如使用F#查询语法,这是一个不错的小功能). 我也不太明白为什么你的代码有两个嵌套的while循环.这有必要吗?如果不是,我想你可以这样写: member this.Work() = async { logger.Info "Starting work" while true do do! Async.Sleep(1000) use context = contextFactory.GetEntities() let unsentEmails = query { for q in context.QueueItems do where (q.Error = null) select q.Email take 10 } unsentEmails |> Array.map MapToMessage |> Array.iter (fun (email,message) -> try mailClient.SendMail(message) email.DateSent <- new Nullable<DateTime>(DateTime.UtcNow) context.QueueItems.Remove(email.QueueItem) |> ignore with ex -> logger.Error(ex) email.QueueItem.Error <- ex.ToString()) context.SaveChanges() |> ignore logger.Info (sprintf "Sent %d emails" unsentEmails.Length) logger.Info "Work complete" } 要开始这个过程(并在以后停止它),你会写下这样的东西: // Start the work let cts = new CancellationTokenSource() Async.Start(worker.Work(),cts.Token) // Stop the worker cts.Cancel() (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
推荐文章
站长推荐
- 从用户空间冻结窗口的方法
- windows-server-2003 – PHP MYSQL站点性能
- Windows2016系统数据中心板远程报错 CredSSP 加密
- 在Windows上使用带有cygwin的anaconda环境
- Windows 上编译 corefx 源码生成 Linux 上可用的
- windows-server-2008 – 你能下载Hyper-V吗?
- windows-8 – 在Windows 8应用程序中为Dispatche
- windows-server-2008 – 32位操作系统可以使用64
- windows-server-2003 – 如何从启动CD获取许可证
- MIT / Scheme是Windows下的一个简单编译器
热点阅读