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

The last parenthesis (4 lines from bottom) closes the using statement. I must be missing something obvious here but the code compiles, passes resharper and yet the var message is used outside the using statement. In fact if I put it inside the using statement it fails to build.

In fact from this https://learn.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): "

message should already have been out of scope and possibly disposed.

RB.
  • 36,301
  • 12
  • 91
  • 131
Simon N
  • 27
  • 3
  • 7
    "The last parenthesis (4 lines from bottom) closes the using statement." No, it doesn't. It closes the declaration, and then the actual statement block begins (containing the single statement `smtp.Send`). – Jeroen Mostert Sep 25 '17 at 10:59
  • 4
    `smtp.Send(message)` is within the `using` block. The `{}` before that is simply the initialization of the `MailMessage`. – Manfred Radlwimmer Sep 25 '17 at 10:59
  • I've reformatted your code to make the above comments clear :) – RB. Sep 25 '17 at 11:02
  • Variables declared inside the using declaration are still within the scope, in fact the way you have it is actually the recommended approach, from the [docs](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/using-statement) - `it is generally better to instantiate the object in the using statement and limit its scope to the using block.`. – James Sep 25 '17 at 11:03

4 Answers4

4

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

No, it closes the resource acquisition. Using statements have this form:

using ( resource_acquisition ) embedded_statement

The embedded_statement can also be a block:

using ( resource_acquisition ) 
{
    embedded_statement
}

The embedded_statement has access to variables created in the resource_acquisition.

To translate that to your code:

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

{                                                            //
    smtp.Send(message);                                      // Embedded statement
}                                                            //
CodeCaster
  • 147,647
  • 23
  • 218
  • 272
2

A basic example of the using statement is this:

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

Here is a shorter example of how you use the using statement:

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

That's equivalent to:

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

So, while spread out over a few lines, your code is still valid:

using (
   var message = new MailMessage(fromAddress, toAddress)
        {
            Subject = subject,
            Body = body,
            IsBodyHtml = true
        }
)
{
    smtp.Send(message);
}
Zohar Peled
  • 79,642
  • 10
  • 69
  • 121
0
var message = new MailMessage(fromAddress, toAddress)
                {
                    Subject = subject,
                    Body = body,
                    IsBodyHtml = true
                }

^^ That's a constructor call and then an object initializer in one go. The next set of braces is the body of the using statement. Look at the parentheses for the actual using keyword - they wrap this whole initiliazation. It's the same as:

var message = new MailMessage(fromAddress, toAddress);
message.Subject = subject;
message.Body = body;
message.IsBodyHtml = true;
thisextendsthat
  • 1,266
  • 1
  • 9
  • 26
0

You're misunderstanding where your using statement ends.

Consider this simple example:

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

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

I assume you see that this simple example is valid.


Object initializers can be used during initialization of an object (= calling the constructor).

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

But when an object initializer sets multiple properties, most developers prefer to split them over new lines:

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

Object initializers can also be used in a using statement:

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

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

And when an object initializer sets multiple properties, most developers prefer to split them over new lines

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

Notice how in all my examples, the body of the using block has never changed.

So when we now look at your example:

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

Maybe it's easier to understand if I turn your object initializer into a single line statement:

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
Flater
  • 12,908
  • 4
  • 39
  • 62