为什么这不在范围之外

时间:2017-09-25 10:56:49

标签: c# using-declaration

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但是var消息在using语句之外使用。事实上,如果我把它放在using语句中,它就无法构建。

事实上,从https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement

开始

" using语句确保即使在对象上调用方法时发生异常,也会调用Dispose。您可以通过将对象放在try块中然后在finally块中调用Dispose来实现相同的结果;实际上,这就是编译器如何翻译using语句。前面的代码示例在编译时扩展为以下代码(注意额外的花括号以创建对象的有限范围):"

消息应该已经超出范围并且可能已经处理掉了。

4 个答案:

答案 0 :(得分:4)

  

最后一个括号(从下面开始的4行)关闭using语句

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

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
}                                                            //

答案 1 :(得分:2)

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);
}

答案 2 :(得分:0)

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;

答案 3 :(得分:0)

您误解了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块的正文 从未更改

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

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