繁体   English   中英

这个C#“关闭”在参数引用中仍然有效吗?

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM