让我们看一下.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()的func。 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()仍然是安全的吗?封闭仍然有效吗?我们将对MailMessage的引用传递给邮件' - 这是引用的副本,仅在setupMailClient()的上下文中有效。我是否在思考它,或者这仍然是安全使用的?
答案 0 :(得分:3)
两个程序的行为都相同。第二个程序更令人困惑,因为sendMail
是创建MailMessage
的方法,所以它是负责处理它的人(按惯例)。它没有处理对象,它调用的方法可能会使其他人阅读代码时感到困惑。在这种情况下,您应该sendMail
处置MailMessage
(这可以通过将其包装在using
中来完成。
我们将对MailMessage的引用传递给' mail' - 这是引用的副本,仅在setupMailClient()的上下文中有效。
仅在setupMailClient
的上下文中有效。它是该对象整个生命周期的有效参考。它只是setupMailClient
上下文中范围内的,这意味着只允许该方法中的代码按名称引用该参数。 Scope and lifetime are very different concepts。 mail
的范围只是那个方法,但是该变量的生命周期可以(并且在这种情况下)比该方法返回(由于闭包)更长。
答案 1 :(得分:2)
是的,它仍然是安全的。在方法的上下文中MailMessage mail
没有改变意义(没有迭代一次又一次地重置它)。
这意味着您的代码使用安全且封闭完好无损。 (你确实知道你最好在这些情况下使用using
,对吗?)
答案 2 :(得分:1)
捕获变量是因为它是函数的参数。所以它不能从函数外部改变(除了对象的状态)。 SmtpClient也是一个局部变量,因此与邮件的范围相同。