为什么这不超出范围

why is this not out of scope

var smtp = new SmtpClient
{
    Host =smtpHost,
    Port = smtpPort,
    EnableSsl = true,
    DeliveryMethod = SmtpDeliveryMethod.Network,
    UseDefaultCredentials = false,
    Credentials = new NetworkCredential(fromAddress.Address, mailFromPassword)
};

using (var message = new MailMessage(fromAddress, toAddress)
    {
        Subject = subject,
        Body = body,
    }
)
{
    smtp.Send(message);
}

最后一个括号(从底部算起 4 行)结束了 using 语句。我一定在这里遗漏了一些明显的东西,但是代码编译,通过了 resharper,但是在 using 语句之外使用了 var 消息。事实上,如果我把它放在 using 语句中,它就无法构建。

其实从这个https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement

"The using statement ensures that Dispose is called even if an exception occurs while you are calling methods on the object. You can achieve the same result by putting the object inside a try block and then calling Dispose in a finally block; in fact, this is how the using statement is translated by the compiler. The code example earlier expands to the following code at compile time (note the extra curly braces to create the limited scope for the object): "

消息应该已经超出范围并且可能已被处置。

var message = new MailMessage(fromAddress, toAddress)
                {
                    Subject = subject,
                    Body = body,
                    IsBodyHtml = true
                }

^^ 这是一次构造函数调用,然后是对象初始值设定项。 next 组大括号是 using 语句的主体。查看实际 using 关键字的括号 - 它们包装了整个初始化。等于:

var message = new MailMessage(fromAddress, toAddress);
message.Subject = subject;
message.Body = body;
message.IsBodyHtml = true;

The last parenthesis (4 lines from bottom) closes the using statement

否,关闭资源获取。使用语句具有以下形式:

using ( resource_acquisition ) embedded_statement

embedded_statement也可以是块:

using ( resource_acquisition ) 
{
    embedded_statement
}

embedded_statement 可以访问在 resource_acquisition 中创建的变量。

将其翻译成您的代码:

using (var message = new MailMessage(fromAddress, toAddress) //
                    {                                        //
                        Subject = subject,                   //
                        Body = body,                         // Resource acquisition
                    }                                        //
      )                                                      //

{                                                            //
    smtp.Send(message);                                      // Embedded statement
}                                                            //

using 语句的一个基本示例是这样的:

using(/*declare and instantiate the instance of IDisposable here*/)
{
    // use it here.
}

以下是如何使用 using 语句的简短示例:

using(var whatever = new IDisposable(parameters) {PropertyName = propertyValue})
{
    whatever.DoStuff();
}

相当于:

try
{
    var whatever = new IDisposable(parameters) {PropertyName = propertyValue};
    whatever.DoStuff();
}
finally
{
    whatever.Dispose();
}

因此,虽然分布在几行中,但您的代码仍然有效:

using (
   var message = new MailMessage(fromAddress, toAddress)
        {
            Subject = subject,
            Body = body,
            IsBodyHtml = true
        }
)
{
    smtp.Send(message);
}

你误解了你的 using 语句在哪里结束。

考虑这个简单的例子:

using(var myObject = new MyObjectClass())
{
    string test = myObject.Name; //IN SCOPE
}

string test2 = myObject.Name; //OUT OF SCOPE

我假设你看到这个简单的例子是有效的。


Object initializers 可以在对象初始化期间使用(=调用构造函数)。

var myObject = new MyObjectClass() { Name = "Donald Trump" };

但是当对象初始值设定项设置多个属性时,大多数开发人员更喜欢将它们拆分成新行:

var myObject = new MyObjectClass() { 
    Name = "Donald Trump" 
    Age = 71,
    Nickname = "Donnie" 
};

对象初始值设定项也可以用在 using 语句中:

using(var myObject = new MyObjectClass() { Name = "Donald Trump" })
{
    string test = myObject.Name; //IN SCOPE
}

string test2 = myObject.Name; //OUT OF SCOPE

当对象初始值设定项设置多个属性时,大多数开发人员更喜欢将它们拆分成新行

using(var myObject = new MyObjectClass() { 
    Name = "Donald Trump" 
    Age = 71,
    Nickname = "Donnie" 
})
{
    string test = myObject.Name; //IN SCOPE
}

string test2 = myObject.Name; //OUT OF SCOPE

请注意,在我的所有示例中,using 块的 body 从未更改过

所以当我们现在看你的例子时:

using (var message = new MailMessage(fromAddress, toAddress)
    {
        Subject = subject,
        Body = body,
    }
)
{
    smtp.Send(message); //IN SCOPE
}

smtp.Send(message); //THIS WOULD BE OUT OF SCOPE

如果我把你的对象初始化器变成单行语句,也许更容易理解:

using (var message = new MailMessage(fromAddress, toAddress) { Subject = subject, Body = body })
{
    smtp.Send(message); //IN SCOPE
}

smtp.Send(message); //THIS WOULD BE OUT OF SCOPE