【问题标题】:why is this not out of scope为什么这不是超出范围
【发布时间】:2018-03-06 07:47:06
【问题描述】:
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 行)结束了 using 语句。"不,它没有。它关闭声明,然后开始实际的语句块(包含单个语句smtp.Send)。
  • smtp.Send(message)using 块内。之前的{}只是MailMessage的初始化。
  • 我已重新格式化您的代码以使上述 cmets 清晰 :)
  • 在 using 声明中声明的变量仍在范围内,实际上您拥有它的方式实际上是推荐的方法,来自docs - it is generally better to instantiate the object in the using statement and limit its scope to the using block.

标签: c# using-declaration


【解决方案1】:
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;

【讨论】:

    【解决方案2】:

    您误解了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
    

    【讨论】:

      【解决方案3】:

      最后一个括号(从底部算起 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
      }                                                            //
      

      【讨论】:

        【解决方案4】:

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

        【讨论】:

          猜你喜欢
          • 2022-08-10
          • 1970-01-01
          • 2022-11-25
          • 1970-01-01
          • 2016-11-22
          • 2013-02-11
          • 1970-01-01
          • 2016-08-22
          • 2015-11-05
          相关资源
          最近更新 更多