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