簡體   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