Reputation: 1384
I have a static StreamWriter field for a log file I need to access through a lambda function that listens to StandardOutput on a long-running Process.
I'm using the null/not-null status of the field to determine if the Process is busy on another thread; the actions need to be performed sequentially.
My question is, what happens when I set my variable to null inside a using block? Will it still get disposed properly?
public class Service
{
private static StreamWriter logger;
void Run(string logFile)
{
using (logger = new StreamWriter(logFile))
{
/* ... */
logger = null;
}
}
}
Upvotes: 4
Views: 1325
Reputation: 5124
My question is, what happens when I set my variable to null inside a using block? Will it still get disposed properly?
That depends on where your variable's declared. It will either be disposed of correctly, or your code won't compile in the first place.
A a;
using (a = new A())
{
a = null;
}
Yes, it will be disposed properly. For a simple test:
My text colour scheme is Ragnarok Grey.
Even with the assignment cleared, a reference to the new A()
seems to have been maintained. a
is disposed of at the end of the using
statement as expected, even if it's nulled inside.
In some versions of Visual Studio, this may result in Compiler Warning (level 2) CS0728:
Possibly incorrect assignment to local 'a' which is the argument to a using or lock statement. The Dispose call or unlocking will happen on the original value of the local.
using (var a = new A())
{
a = null;
}
The above code won't compile. You're not permitted to assign to a using
variable in the first place. The above code produces this compile error:
Cannot assign to 'a' because it is a 'using variable'
This is Compiler Error CS1656.
This error occurs when an assignment to variable occurs in a read-only context. Read-only contexts include foreach iteration variables, using variables, and fixed variables. To resolve this error, avoid assignments to a statement variable in using blocks, foreach statements, and fixed statements.
Upvotes: 2
Reputation: 942267
This is not a problem. You'd have to look at the IL with ildasm.exe to see how the compiler does this. But it generates an extra variable to store a reference to the object so you cannot shoot your foot like this. The equivalent C# code would (roughly) look like this:
StreamWriter $temp = new StreamWriter(logFile);
logger = $temp;
try {
// etc...
logger = null;
}
finally {
if ($temp != null) $temp.Dispose();
}
That extra $temp variable keeps you out of trouble.
Upvotes: 2
Reputation: 273711
According to the C# reference, § 8.13, your code:
private static StreamWriter logger;
using (logger = new StreamWriter(logFile))
{
/* ... */
logger = null;
}
is equivalent to
private static StreamWriter logger;
{ // using scope
logger = new StreamWriter(logFile);
IDisposable resource = logger; // hidden var inserted by the compiler
try
{
/* ... */
logger = null;
}
finally
{
if (resource != null)
resource.Dispose();
}
}
The relevant quote:
A using statement of the form
using (expression) statement
has the same three possible expansions, but in this case ResourceType is implicitly the compile-time type of the expression, and the resource variable is inaccessible in, and invisible to, the embedded statement.
Upvotes: 3