[英]Is this C# 'closure' still valid across a parameter reference?
让我们以.NET SmtpClient为例,您可以执行以下操作(忽略凭据,SSL和异常处理):
async Task sendMail()
{
var m = new MailMessage(...);
var s = new SmtpClient(host, port);
s.SendCompleted += (s, e) => { m.Dispose(); s.Dispose(); };
await s.SendMailAsync(m);
}
一切都很好; 每当异步发送完成时,将调用进行Dispose()处理的函数。 m和s在声明它的包含范围内,所以在那里没有问题。
但是说我们有以下几点:
SmtpClient setupMailClient(MailMessage mail)
{
var smtpClient = new SmtpClient(host, port);
smtpClient.SendCompleted += (s, e) => { mail.Dispose(); smtpClient.Dispose(); };
return smtpClient;
}
async Task sendMail()
{
var m = new MailMessage(...);
var s = setupMailClient(m);
await s.SendMailAsync(m);
}
现在,调用await sendMail()仍然安全吗? 关闭仍然有效吗? 我们以“ mail”的形式传递对MailMessage的引用-这是引用的副本,仅在setupMailClient()的上下文中有效。 我是不是想得太多,还是仍然可以安全使用?
这两个程序的行为相同。 第二个程序很难遵循,因为sendMail
是创建MailMessage
的方法,因此它是负责处理它的程序(按照惯例)。 它不处理该对象,而调用它的方法则可能会使其他人混淆阅读代码。 在这种情况下,您确实应该让sendMail
处理MailMessage
(只需将其包装在using
就可以完成。
我们以“ mail”的形式传递对MailMessage的引用-这是引用的副本,仅在setupMailClient()的上下文中有效。
这不仅在上下文中有效setupMailClient
。 这是该对象整个生命周期的有效参考。 它仅在 setupMailClient
范围内 ,这意味着仅该方法内的代码被允许按名称引用该参数。 范围和寿命是非常不同的概念 。 mail
的范围就是该方法,但是该变量的生存期(在这种情况下可以)比该方法返回之前(由于关闭)要长得多。
是的,它仍然安全。 在MailMessage mail
方法的上下文中, MailMessage mail
的含义没有改变(没有迭代过程可以一遍又一遍地重置它)。
这意味着您的代码可以安全使用,并且闭包是完整的。 (你知道你最好使用using
对于这些情况,对吧?)
捕获变量是因为它是函数的参数。 因此,不能从函数外部进行更改(对象状态除外)。 SmtpClient也是一个局部变量,因此与邮件的作用域相同。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.