Assign to a using variable before it is disposed - c#

Can you assign to a variable instantiated in a using statement before it is disposed at the end. E.g.
using (TempObj temp = new TempObj())
{
temp.doStuff(......);
realObj = temp; // <-------- Is this line ok?
}
If not why can't you?
Edit: I mean what will happen to realObj in this situation

It is possible, but realObj will hold an instance of a disposed object.
Do not use variables created in using() outside the using block.

Related

Does using dispose objects if they are declared in a method

Let's say I create a disposable object in a method, but I will call a using out of the method. Is then everything disposed in this method?
using(DbConnection connection = new DbConnection("myConnection"){
SomeMethod();
}
public void SomeMethod(){
var stream = new MemoryStream()
// ... Do something with the stream ...
}
Is the stream created in the 'SomeMethod' then disposed?
No, it won't be. Only the reference explicitly specified in the using statement will be disposed.
In this case, only connection will be disposed after the code execution leaves the using block. You'll need to also wrap var stream = .. in a using block, or manually dispose it.
when we use Using keyword,it will call dispose method of object which is created in
using(Form m =new Form()) bracket. so remember we have to dispose manually if anything to dispose in the scope which is defined by {}
Example:
using(Form test =new Form())//test object will disposed by using at end of scope
{//Scope start
//code written here or created new object are not disposed by using
//Scope End
}

Object lifetime when created and used only in the scope of a using statement

When an object is created and used only within the scope of a using statement, is it disposed of during the disposal of its enclosing IDisposable instance? If not, why wouldn't it be?
For instance, when using Dapper I've often created an anonymous object within the scope of the SqlConnection with the impression that it will be disposed of sooner - however I recently read something to the contrary.
using (var connection = new SqlConnection("Connection String"))
{
var parameters = new
{
Message = "Hello world!"
};
connection.Execute("INSERT INTO...", parameters);
}
Your using statement is essentially equivalent to:
var connection = new SqlConnection("Connection String");
try
{
var parameters = new
{
Message = "Hello world!"
};
}
finally
{
if (connection != null)
{
((IDisposable)connection).Dispose();
}
}
As you can see, there is no reason why any other IDisposable instance created inside the try block be disposed automatically for you. If you do need to ensure other objects are disposed then simply nest using statements:
using (var connection = new SqlConnection("Connection String"))
{
using (var otherDisposableObject = new ....)
{
} //otherDisposableObject disposed
} //connection disposed
If excessive nesting gets in the way of readability, then you can simply write the using statements as follows:
using (var connection = new SqlConnection("Connection String"))
using (var otherDisposableObject = new ....)
using (var anotherDisposableObject = new ....)
using (var andAnotherDisposableObject = new ....)
{
} //andAnotherDisposableObject, anotherDisposableObject, otherDisposableObject and connection all disposed
Do bear in mind though that you seem to be mixing garbage collection with disposing an object. In your example, parameters is elegible for garbage collection once execution has exited the using statement as there is no live refence to it.
When it is garbage collected is up to the GC, it might very well never be, depending on your application's memory pressure. If it is garbage collected, then it will be marked as valid for finalization and the finalizer of the object will be scheduled to run. Again, if and when that happens is entirely up to the GC.
Lastly, if the IDisposable pattern of the object is implemented correctly and the finalizer is run, Dispose() will be called (to be precise, Dispose(false) will be called) and the object will dispose any unmanaged resources it might be holding (managed resources can not be disposed safely in this context but it really doesn't matter, the GC will eventually take care of them too).
See IDisposable Pattern for more details on how it works or even better, check out this excellent SO answer.

Enumerator disposal when not using using, foreach or manually calling Dispose()

I'm using yield return to iterate over an SqlDataReader's records:
IEnumerable<Reading> GetReadings() {
using (var connection = new SqlConnection(_connectionString))
{
using (var command = new SqlCommand(_query, connection))
{
connection.Open();
using (var reader = command.ExecuteReader())
{
while (reader.Read())
{
yield return new Reading
{
End = reader.GetDateTime(0),
Value = reader.GetDouble(1)
};
}
}
connection.Close();
}
}
}
I'm then using an adapted version of this accepted answer to "zip" many iterators together:
var enumerators = data.Select(d => new
{
d.Key,
Enumerator = d.Value.GetEnumerator()
}).ToList();
while (true)
{
foreach (var item in enumerators)
{
if (!item.Enumerator.MoveNext())
{
yield break;
}
/*snip*/
}
/*snip*/
}
In the method above, the enumerator's Dispose() is not explicitly called, and because they are not used within a using or foreach statement, would the underlying iterator remain in an open state? In my case with an open SqlConnection.
Should I be calling Dispose() on the enumerators to make sure the whole downstream chain is closed?
When enumerating over this iterator, if the enumerator's Dispose() is not explicitly called, and not used within a using statement, would the underlying iterator remain in an open state?
Let me re-phrase that question into a form that is easier to answer.
When using foreach to enumerate via an iterator block that contains a using statement, are the resources disposed of when control leaves the loop?
Yes.
What mechanisms ensure this?
These three:
A using statement is just a convenient way to write a try-finally where the finally disposes of the resource.
The foreach loop is also a convenient syntax for try-finally, and again, the finally calls Dispose on the enumerator when control leaves the loop.
The enumerator produced by an iterator block implements IDisposable. Calling Dispose() on it ensures that all the finally blocks in the iterator block are executed, including finally blocks that come from using statements.
If I avoid the foreach loop, call GetEnumerator myself, and don't call Dispose on the enumerator, do I have a guarantee that the finally blocks of the enumerator will run?
Nope. Always dispose your enumerators. They implement IDisposable for a reason.
Is that now clear?
If this subject interests you then you should read my long series on design characteristics of iterator blocks in C#.
http://blogs.msdn.com/b/ericlippert/archive/tags/iterators/
You call Dispose to deallocate resources allocated by the connection and call Close to just close the connection. AfterClose call the connection may be pushed in connection pool, if runtime that found suitable, in case of Dispose, instead, it will be scheduled for destroy .
So all depends on what you mean saying "valid" state.
If it's enclosed in usingdirrective, which is nothing else then try/finally, you have a guarantee that even if any exception happen in iteration the connection will be closed and its resources will be destroyed. In other cases you have to handle all it by yourself.
Just to add some nuance to this:
Array-enumerators are NOT generic and are not disposable
Collection-enumerators ARE generic of and are disposable but only if T itself is a reference-type ... not a value-type
So if you use GetEnumerator(), be sure to use
IEnumerator arrayEnumerator = arrayToEnumerate.GetEnumerator();
IEnumerator<T> collectionEnumerator = collectionToEnumerate.GetEnumerator();
then later in your code
collectionEnumerator.Dispose(); // compiles if T is reference-type but NOT value-type
Examples:
object[] theObjectArray = [...]
IEnumerator arrayEnumerator = theObjectArray.GetEnumerator(); // does not return
IEnumerator<object> and is not disposable
arrayEnumerator.Dispose(); // won't compile
List<double> theListOfDoubles = [...]
IEnumerator<someObject> doubleEnumerator = doubleEnumerator.GetEnumerator();
doubleEnumerator.Dispose(); // won't compile
List<someObject> theListOfObjects = [...]
IEnumerator<someObject> objectEnumerator = theListOfObjects.GetEnumerator(); // disposable
objectEnumerator.Dispose(); // compiles & runs

Does `using` dispose all the the objects declared in it?

I wonder if the object created in the usingstatement gets disposed if I perform a return or throw operation. Example as follows.
using(SomeClass thing = new SomeClass())
{
...
if(condition)
return;
...
}
Will the above get confused or is GC to be trusted here?
Yes, it will. The using statement will result in a finally block being created. A finally block's code will be run even if an exception is thrown in the related try block, or if there is a return statement in that try block.
There are only a few exceptions that can cause a finally block's code to not be executed, and they are all listed here, but my guess is that in your situation you'll be able to live with those consequences.
using is the equivalent of try-finally so, yes, it does.
dispose if it is implemented will always get called. Its the equivalent of calling dispose in a finally block.
It will dispose, yes. It will create a finally block in the CIL code.
Yes, because using is extended into a try finally by the compiler. The dispose will occur inside the finally block. Also, the finally will contain a test to check if the variables in the using are null (in case there are exceptions on the constructors).
When writing a using statement:
using(SomeClass thing = new SomeClass())
{
//...
if (condition)
return;
//...
}
this will result in the following code:
SomeClass thing;
try
{
thing = new SomeClass();
//...
if (condition)
return;
//...
}
finally
{
if(thing != null)
{
thing.Dispose();
}
}
So all object declared using ( /* HERE */ ) will get disposed automatically. Objects declared inside the {} won't.
But you can of course nest (or stack) using statements:
using (var thing = new SomeClass())
using (var another = new Another())
using (var somethingElse = new Whatever())
{
//...
}
which in turn of course is just the syntactic sugar for writing
using (var thing = new SomeClass())
{
using (var another = new Another())
{
using (var somethingElse = new Whatever())
{
//...
}
}
}
because when a statement is followed by just one block of code (in this case another using-block) you can skip the curly braces...
When using two or more objects of the same type you can chain the declaratio within the using-statement:
using (MemoryStream stream = new MemoryStream(), stream2 = new MemoryStream())
{
//...
}
(Thanks to #Gratzy for pointing that out)
For me, the question does not match with the details, and the details have been addressed here a bunch but not the title question...
Does using dispose all the the objects declared in it?
NO, it does not. It only calls Dispose() for the object(s) in its declaration. It does not call Dispose() for objects declared in it.
I usually see this kind of thing in code
using(var sqlConn = new SqlConnection("connStr"))
using(var sqlCmd = new SqlCmd("CmdText", sqlConn))
{
sqlConn.Open();
var reader = sqlCmd.ExecuteReader();
while (reader.Read())
{
//stuff is done
}
}
This will dispose and close both sqlConn and sqlCmd when the scope is complete for those but the reader that was declared in the using scope does not have Dispose() automatically called for it .

Why can't I get rid of a CA2000 warning?

I'm writing a method that resets a logging system. I need to get an instance of a CsvFileLogWriter (a custom class) and pass it to the reset method. CsvFileLogWriter is disposable so I get a CA2000 warning tell me:
Warning 2 CA2000 : Microsoft.Reliability : In method 'Logger.InitializeCsvLogger
(string)', call System.IDisposable.Dispose on object 'tempWriter'
before all references to it are out of scope.
I've followed the instructions relating to CA2000 and I end up with the following method. However, I still get the CA2000 warning.
public static void InitializeCsvLogger(string path)
{
ILogWriter tempWriter = null;
try
{
tempWriter = new CsvFileLogWriter(path);
ResetWriter(tempWriter);
tempWriter = null;
}
finally
{
if (tempWriter != null)
tempWriter.Dispose();
}
}
Can someone please spot my mistake?
EDIT
I do not wish to dispose of the writer that is reference by tempWriter - this is not a temporary object, just a temporary reference. I only dispose of it if there is a failure within the try block (so tempWriter never gets set to null and the if-statement in the finally block clears up the resources.) I do not want tempWriter disposing of unless this failure occurs - the object itself must remain in use after being set in a property by ResetWriter(tempWriter). This is as per the CA2000 rules - see http://msdn.microsoft.com/en-us/library/ms182289.aspx?queryresult=true
For clarification, here is what ResetWriter does - Writer is a static property. The method disposes the old writer and sets the new one.
private static void ResetWriter(ILogWriter newWriter)
{
if (Writer != null)
Writer.Dispose();
Writer = newWriter;
}
EDIT
I think as SLaks stated that it's a false positive. If I take the contents of ResetWriter and put them in place of the call to ResetWriter (essentially reversing an Extract Method refactoring) the CA2000 goes away.
Or in other words, the following does not give the CA2000 warning:
public static void InitializeCsvLogger(string path)
{
ILogWriter tempWriter = null;
try
{
tempWriter = new CsvFileLogWriter(path);
if (Writer != null)
Writer.Dispose();
Writer = tempWriter;
tempWriter = null;
}
finally
{
if (tempWriter != null)
tempWriter.Dispose();
}
}
When you assign null to tempWriter:
tempWriter = null;
tempWriter no longer refers to the object you created. Therefore, there's no way for you to Dispose the object.
You should really use a using block in this case instead:
using(var tempWriter = new CsvFileLogWriter(path))
{
ResetWriter(tempWriter);
}
By doing that, you no longer have to worry about calling Dispose (or setting the reference to null).
This warning is a false positive.
The Code Analysis engine doesn't realize that ResetWriter needs the writer to stay alive, so it wants you to dispose it in all circumstances.
You should suppress the warning.
By writing tempWriter = null you're preventing it from getting disposed, since the finally block only runs after that.
You should use the using statement instead.
This answer is correct, but contradicts your actual intentions.

Categories

Resources