Suppose I have defined the followed method.
static object F()
{
return new object();
}
If I write code like the following, the returned object cannot be garbage collected until the end of the scope.
{
object x = F();
// cannot yet garbage collect the object
// returned by F (referenced as variable x)
}
// can now garbage collect the object
// returned by F (referenced as variable x)
If I write code like the following, the returned object can be garbage collected immediately after F returns.
{
F();
// can now garbage collect the object
// returned by F
}
But now suppose I change the definition of F to the following.
static IDisposable F()
{
return new SomeDisposableObject();
}
If I write code like the following, the returned object cannot be garbage collected and will not be disposed until the end of the using block.
using (IDisposable x = F())
{
} // immediately x.Dispose()
// can now garbage collect the object
// returned by F
If I write code like the following, what is the behavior? References to C# language specification are a plus.
using (F())
{
}
Does the using block count as a reference to the instance returned by F?
Yes.
You cannot dispose something without a reference to it.
The spec states that using (expression) { statement } is compiled to:
{
ResourceType resource = expression;
try {
statement;
}
finally {
if (resource != null) ((IDisposable)resource).Dispose();
}
}
resource is a reference.
There is no implicit reference to a local variable at the end of a scope. An implementation may, but is not required to, garbage collect an object after your last actual reference to it. In other words, your second code block is not correct, because x is allowed to be collected before the end of the block.
{
object x = F();
// <-- x IS ALLOWED to be collected here
Thread.Sleep(5000);
// <-- The object x ref'd IS ALLOWED to be collected here, if it wasn't earlier
}
// <-- The object x ref'd IS ALLOWED to be collected here, if it wasn't earlier
A using block creates a local variable in order to call Dispose at the end of the using block. Even if you do not explicitly name the variable, the reference will be alive until the end of the block.
using (F())
{
// The instance returned by F IS NOT allowed to be collected here
Thread.Sleep(5000);
// The instance returned by F IS NOT allowed to be collected here
}
// The instance returned by F IS allowed to be collected here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With