With the new C# 8 Using Declaration Syntax, what is containing scope of a second consecutive using statement?
TL;DR
Previous to C# 8, having a consecutive using statement like:
using(var disposable = new MemoryStream())
{
using(var secondDisposable = new StreamWriter(disposable))
{}
}
would expand to something like the following (My Source):
MemoryStream disposable = new MemoryStream();
try {
{
StreamWriter secondDisposable = new StreamWriter(disposable);
try{
{}
}
finally {
if(secondDisposable != null) ((IDisposable)secondDisposable).Dispose();
}
}
}
finally {
if(disposable != null) ((IDisposable)disposable).Dispose();
}
I know that there are two other possible expansions but they all are roughly like this
After upgrading to C# 8, Visual studio offered a Code Cleanup suggestion that I'm not certain I believe is an equivalent suggestion.
It converted the above consecutive using statement to:
using var disposable = new MemoryStream();
using var secondDisposable = new StreamWriter(disposable);
To me this changes the second's scope to the same scope as the first. In this case, It would probably coincidentally dispose of the streams in the correct order, but I'm not certain I like to rely on that happy coincidence.
To be clear on what VS asked me to do: I first converted the inner (which made sense because the inner was still contained in the outer's scope). Then I converted the outer (which locally made sense because it was still contained in the method's scope). The combination of these two clean ups is what I'm curious about.
I also recognize that my thinking on this could be slightly (or even dramatically) off, but as I understand it today, this doesn't seem correct. What is missing in my assessment? Am I off base?
The only thing I can think of is that there is some sort of an implicit scope inserted in the expansion for everything following a declaration statement.
In this case, It would probably coincidentally dispose of the streams in the correct order, but I'm not certain I like to rely on that happy coincidence.
From the spec proposal:
The using locals will then be disposed in the reverse order in which they are declared.
So, yes, they already thought about it and do the disposal in the expected order, just as chained using statements would before it.
To Illustrate the Daminen's answer; When you have a method something like;
public void M()
{
using var f1 = new System.IO.MemoryStream(null,true);
using var f2 = new System.IO.MemoryStream(null,true);
using var f3 = new System.IO.MemoryStream(null,true);
}
IL converts it into;
public void M()
{
MemoryStream memoryStream = new MemoryStream(null, true);
try
{
MemoryStream memoryStream2 = new MemoryStream(null, true);
try
{
MemoryStream memoryStream3 = new MemoryStream(null, true);
try
{
}
finally
{
if (memoryStream3 != null)
{
((IDisposable)memoryStream3).Dispose();
}
}
}
finally
{
if (memoryStream2 != null)
{
((IDisposable)memoryStream2).Dispose();
}
}
}
finally
{
if (memoryStream != null)
{
((IDisposable)memoryStream).Dispose();
}
}
}
Which is same as nested using statements
you can check from here: https://sharplab.io/#v2:CYLg1APgAgTAjAWAFBQMwAJboMLoN7LpGYZQAs6AsgBQCU+hxTUADOgG4CGATugGZx0AXnQA7AKYB3THAB0ASQDysyuIC2Ae24BPAMoAXbuM5rqogK4AbSwBpD58bQDcTRkyKsOPfjGFipMgrKqpo6BkYmZla29o5Obu6eXLx8GCIS0lBySirqWnqGxqYW1nbcDs4JAL7IVUA===
I'd like to see the real function that's using this. The compiler won't change scope or sequence of allocations or disposals willy-nilly. If you have a method like:
void foo()
{
using(var ms = new MemoryStream())
{
using(var ms2 = new MemoryStream())
{
/// do something
}
}
}
Then the Dispose() order doesn't matter, so it's safe for the compiler to arrange things however it sees fit. There may be other cases where the order is important, and the compiler should be smart enough to recognize that. I wouldn't file that under "coincidence" so much as "good AST analysis."
Related
Consider the following method...
private string[] GetExistingPOWSNumbers()
{
using (
var OleAdapter =
new OleDbDataAdapter(
"SELECT DISTINCT con_num FROM `Items` WHERE con_num LIKE 'POWS%'",
ConfigurationManager.ConnectionStrings["MPOleConnectionString"].ConnectionString))
using (var POWSTable = new DataTable())
{
OleAdapter.SelectCommand.Connection.Open();
OleAdapter.Fill(POWSTable);
return POWSTable.AsEnumerable().Select(row => Convert.ToString(row["con_num"])).ToArray();
}
}
Are all the ADO.NET objects promptly being disposed of? I am using this method throughout my projects and when there are A LOT of calls like these being made during a single action, I receive "Out of Memory" errors.
EDIT: After some personal investigation I discovered that, in fact, the using statement for the adapter DOES NOT also close the provided collection. I made the following change. Now I am using a DataReader instead of populating a DataTable.
private string[] GetExistingPOWSNumbers()
{
var Results = new List<string>();
using (var OleConnection = new OleDbConnection(ConfigurationManager.ConnectionStrings["MPOleConnectionString"].ConnectionString))
using (
var OleCommand =
new OleDbCommand(
"SELECT DISTINCT con_num FROM `Items` WHERE con_num LIKE 'POWS%'",
OleConnection))
{
OleConnection.Open();
using (var OleReader = OleCommand.ExecuteReader(CommandBehavior.CloseConnection))
{
if (OleReader == null) return new string[0];
while (OleReader.Read())
{
Results.Add(OleReader.GetString(0));
}
}
}
return Results.ToArray();
}
Objects will be cleaned up when they are no longer being used and when the garbage collector sees fit. Sometimes, you may need to set an object to null in order to make it go out of scope (such as a static field whose value you no longer need), but overall there is usually no need to set to null.
Regarding disposing objects, I agree with #Andre. If the object is IDisposable it is a good idea to dispose it when you no longer need it, especially if the object uses unmanaged resources. Not disposing unmanaged resources will lead to memory leaks.
You can use the using statement to automatically dispose an object once your program leaves the scope of the using statement.
using (MyIDisposableObject obj = new MyIDisposableObject())
{
// use the object here
} // the object is disposed here
Which is functionally equivalent to:
MyIDisposableObject obj;
try
{
obj = new MyIDisposableObject();
}
finally
{
if (obj != null)
{
((IDisposable)obj).Dispose();
}
}
Got this from Zach Johnson here: Credit Due
Most of the examples of the using statement in C# declare the object inside the brackets like this:
using (SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", connection))
{
// Code goes here
}
What happens if I use the using statement in the following way with the object declared outside the using statement:
SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", connection);
using (cmd)
{
// Code goes here
}
Is it a bad idea to use the using statement in the way I have in the second example and why?
Declaring the variable inside the using statement's control expression limits the scope of the variable to inside the using statement. In your second example the variable cmd can continue to be used after the using statement (when it will have been disposed).
Generally it is recommended to only use a variable for one purpose, limiting its scope allows another command with the same name later in scope (maybe in another using expression). Perhaps more importantly it tells a reader of your code (and maintenance takes more effort than initial writing) that cmd is not used beyond the using statement: your code is a little bit more understandable.
Yes, that is valid - the object will still be disposed in the same manner, ie, at the end and if execution flow tries to leave the block (return / exception).
However if you try to use it again after the using, it will have been disposed, so you cannot know if that instance is safe to continue using as dispose doesn't have to reset the object state. Also if an exception occurs during construction, it will not have hit the using block.
I'd declare and initialize the variable inside the statement to define its scope. Chances are very good you won't need it outside the scope if you are using a using anyway.
MemoryStream ms = new MemoryStream(); // Initialisation not compiled into the using.
using (ms) { }
int i = ms.ReadByte(); // Will fail on closed stream.
Below is valid, but somewhat unnecessary in most cases:
MemoryStream ms = null;
using (ms = new MemoryStream())
{ }
// Do not continue to use ms unless re-initializing.
I wrote a little code along with some unit tests. I like it when I can validate statements about the question at hand. My findings:
Whether an object is created before or in the using statement doesn't matter. It must implement IDisposable and Dispose() will be called upon leaving the using statement block (closing brace).
If the constructor throws an exception when invoked in the using statement Dispose() will not be invoked. This is reasonable as the object has not been successfully constructed when an exception is thrown in the constructor. Therefore no instance exists at that point and calling instance members (non-static members) on the object doesn't make sense. This includes Dispose().
To reproduce my findings, please refer to the source code below.
So bottom line you can - as pointed out by others - instantiate an object ahead of the using statement and then use it inside the using statement. I also agree, however, moving the construction outside the using statement leads to code that is less readable.
One more item that you may want to be aware of is the fact that some classes can throw an exception in the Dispose() implementation. Although the guideline is not to do that, even Microsoft has cases of this, e.g. as discussed here.
So here is my source code include a (lengthy) test:
public class Bar : IDisposable {
public Bar() {
DisposeCalled = false;
}
public void Blah() {
if (DisposeCalled) {
// object was disposed you shouldn't use it anymore
throw new ObjectDisposedException("Object was already disposed.");
}
}
public void Dispose() {
// give back / free up resources that were used by the Bar object
DisposeCalled = true;
}
public bool DisposeCalled { get; private set; }
}
public class ConstructorThrows : IDisposable {
public ConstructorThrows(int argument) {
throw new ArgumentException("argument");
}
public void Dispose() {
Log.Info("Constructor.Dispose() called.");
}
}
[Test]
public void Foo() {
var bar = new Bar();
using (bar) {
bar.Blah(); // ok to call
}// Upon hitting this closing brace Dispose() will be invoked on bar.
try {
bar.Blah(); // Throws ObjectDisposedException
Assert.Fail();
}
catch(ObjectDisposedException) {
// This exception is expected here
}
using (bar = new Bar()) { // can reuse the variable, though
bar.Blah(); // Fine to call as this is a second instance.
}
// The following code demonstrates that Dispose() won't be called if
// the constructor throws an exception:
using (var throws = new ConstructorThrows(35)) {
}
}
The idea behind using is to define a scope, outside of which an object or objects will be disposed.
If you declare the object you are about to use inside using in advance, there's no point to use the using statement at all.
It has been answered and the answer is: Yes, it's possible.However, from a programmers viewpoint, don't do it! It will confuse any programmer who will be working on this code and who doesn't expect such a construction. Basically, if you give the code to someone else to work on, that other person could end up being very confused if they use the "cmd" variable after the using. This becomes even worse if there's even more lines of code between the creation of the object and the "using" part.
This question already has answers here:
Closed 13 years ago.
I see loads of code snippets with the following Syntax
using (RandomType variable = new RandomType(1,2,3))
{
// A bunch of code here.
}
why not just declare the variable and use it?
This Using syntax seems to just clutter the code and make it less readable. And if it's so important that that varible is only available in that scope why not just put that block in a function?
Using has a very distinct purpose.
It is designed for use with types that implement IDisposable.
In your case, if RandomType implements IDisposable, it will get .Dispose()'d at the end of the block.
using (RandomType variable = new RandomType(1,2,3))
{
// A bunch of code here.
}
is pretty much the same (with a few subtle differences) as:
RandomType variable = new RandomType(1,2,3);
try
{
// A bunch of code
}
finally
{
if(variable != null)
variable.Dispose()
}
Note that when calling "Using", you can cast anything as IDisposable:
using(RandomType as IDisposable)
The null check in the finally will catch anything that doesn't actually implement IDisposable.
No, it does not clutter your code , or make it less readable.
A using statement can only be used on IDisposable types (that is, types that implement IDisposable).
By using that type in a using - block, the Dispose method of that type will be used when the scope of the using-block ends.
So, tell me which code is less readable for you:
using( SomeType t = new SomeType() )
{
// do some stuff
}
or
SomeType t = new SomeType();
try
{
// do some stuff
}
finally
{
if( t != null )
{
t.Dispose();
}
}
An object being used in a using statement must implement IDisposable, so at the end of the scope, you're guaranteed that Dispose() will be called, so theoretically, your object should be released at that point. In some cases, I've found it makes my code clearer.
The using keyword provides a deterministic way to clean up the managed or unmanaged resources that an object allocates. If you don't use the using keyword, you are responsible to call Dispose() (or in some cases, Close()) when finished with that object. Otherwise, the resources may not be cleaned up until the next garbage collection, or even not at all.
According to MSDN, the following using code:
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
expands to this:
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
And it does really not clutter your code. Quite the opposite actually!
I was reading another answer. And it made me wonder, when do does one need to explicitly call Dispose if I am using using statements?
EDIT:
Just to vindicate myself from being a total know-nothing, the reason I asked was because someone on another thread said something implying there was a good reason to have to call Dispose manually... So I figured, why not ask about it?
You don't. The using statement does it for you.
According to MSDN, this code example:
using (Font font1 = new Font("Arial", 10.0f))
{
byte charset = font1.GdiCharSet;
}
is expanded, when compiled, to the following code (note the extra curly braces to create the limited scope for the object):
{
Font font1 = new Font("Arial", 10.0f);
try
{
byte charset = font1.GdiCharSet;
}
finally
{
if (font1 != null)
((IDisposable)font1).Dispose();
}
}
Note: As #timvw mentioned, if you chain methods or use object initializers in the using statement itself and an exception is thrown, the object won't be disposed. Which makes sense if you look at what it will be expanded to. For example:
using(var cat = new Cat().AsDog())
{
// Pretend a cat is a dog
}
expands to
{
var cat = new Cat().AsDog(); // Throws
try
{
// Never reached
}
finally
{
if (cat != null)
((IDisposable)cat).Dispose();
}
}
AsDog will obviously throw an exception, since a cat can never be as awesome as a dog. The cat will then never be disposed of. Of course, some people may argue that cats should never be disposed of, but that's another discussion...
Anyways, just make sure that what you do using( here ) is safe and you are good to go. (Obviously, if the constructor fails, the object won't be created to begin with, so no need to dispose).
Normally you don't. This is the point of the using statement. There is however a situation where you have to be careful:
If you reassign the variable to another value the using statement will only call the Dispose method on the original value.
using (someValue = new DisposableObject())
{
someValue = someOtherValue;
}
The compiler will even give you a Warning about this:
Possibly incorrect assignment to local 'someValue' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
Be careful when using c# 3.0 object initializers though. An example can be found here: http://ayende.com/Blog/archive/2009/01/15/avoid-object-initializers-amp-the-using-statement.aspx
Never. It will call Dispose once the statements inside using blocks finish execution.
The whole point of the using statement is that if your object implements IDisposable, the dipose will be called at the end of the code block. That's what it's there for, to do it automaticaly for you.
As far as i know
using (var myDisposable = new MyDisposable())
{
...
}
is basically translated by the compiler to
var myDisposable = new MyDisposable()
try
{
...
}
finally
{
myDisposable.Dispose();
}
Something like:
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
I believe it is not a proper place for a return statement, is it?
As several others have pointed out in general this is not a problem.
The only case it will cause you issues is if you return in the middle of a using statement and additionally return the in using variable. But then again, this would also cause you issues even if you didn't return and simply kept a reference to a variable.
using ( var x = new Something() ) {
// not a good idea
return x;
}
Just as bad
Something y;
using ( var x = new Something() ) {
y = x;
}
It's perfectly fine.
You are apparently thinking that
using (IDisposable disposable = GetSomeDisposable())
{
//.....
//......
return Stg();
}
is blindly translated into:
IDisposable disposable = GetSomeDisposable()
//.....
//......
return Stg();
disposable.Dispose();
Which, admittedly, would be a problem, and would make the using statement rather pointless --- which is why that's not what it does.
The compiler makes sure that the object is disposed before control leaves the block -- regardless of how it leaves the block.
It's absolutely fine - no problem at all. Why do you believe it's wrong?
A using statement is just syntactic sugar for a try/finally block, and as Grzenio says it's fine to return from a try block too.
The return expression will be evaluated, then the finally block will be executed, then the method will return.
This will work perfectly fine, just as returning in the middle of try{}finally{}
That is totally acceptable. A using statement ensures the IDisposable object will be disposed no matter what.
From MSDN:
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 bellow shows how using is working:
private class TestClass : IDisposable
{
private readonly string id;
public TestClass(string id)
{
Console.WriteLine("'{0}' is created.", id);
this.id = id;
}
public void Dispose()
{
Console.WriteLine("'{0}' is disposed.", id);
}
public override string ToString()
{
return id;
}
}
private static TestClass TestUsingClose()
{
using (var t1 = new TestClass("t1"))
{
using (var t2 = new TestClass("t2"))
{
using (var t3 = new TestClass("t3"))
{
return new TestClass(String.Format("Created from {0}, {1}, {2}", t1, t2, t3));
}
}
}
}
[TestMethod]
public void Test()
{
Assert.AreEqual("Created from t1, t2, t3", TestUsingClose().ToString());
}
Output:
't1' is created.
't2' is created.
't3' is created.
'Created from t1, t2, t3' is created.
't3' is disposed.
't2' is disposed.
't1' is disposed.
The disposed are called after the return statement but before the exit of the function.
Perhaps it isn't 100% true that this is acceptable...
If you happen to be nesting usings and returning from within a nested one, it might not be safe.
Take this as an example:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
return memoryStream.ToArray();
}
}
}
I was passing in a DataTable to be outputted as csv. With the return in the middle, it was writing all the rows to the stream, but the outputted csv was always missing a row (or multiple, depending on the size of the buffer). This told me that something wasn't being closed properly.
The correct way is to make sure all the previous usings are disposed properly:
using (var memoryStream = new MemoryStream())
{
using (var textwriter = new StreamWriter(memoryStream))
{
using (var csv = new CsvWriter(textwriter))
{
//..write some stuff to the stream using the CsvWriter
}
}
return memoryStream.ToArray();
}