Using `using(...)` effectively useless and/or inefficient?
Does the following code render the using(...)
function/purpose irrelevant?
class Program
{
static Dictionary<string , DisposableClass> Disposables
{
get
{
if (disposables == null)
disposables = new Dictionary<string , DisposableClass>();
return disposables;
}
}
static Dictionary<string , DisposableClass> disposables;
static void Main(string[] args)
{
DisposableClass disposable;
using (disposable = new DisposableClass())
{
// do some work
disposable.Name = "SuperDisposable";
Disposables["uniqueID" + Disposables.Count] = disposable;
}
Console.WriteLine("Output: " + Disposables["uniqueID0"].Name);
Console.ReadLine();
}
}
class DisposableClass : IDisposable
{
internal string Name
{
get { return myName; }
set { myName = value; }
}
private string myName;
public void Dispose( )
{
//throw new NotImplementedException();
}
}
Output: SuperDisposable
My understanding of the using(...)
function is to immediately coerce disposal of the DisposableClass
. Yet within the code block, we are adding the class to a dictionary collection. My understanding is that a class is inherently a reference type. So my experiment was to see what would happen to the disposable object added to a collection in this manner.
In this case DisposableClass
is still quite alive. Classes are a reference type - so my assumption then became that the collection is not simply referencing this type, but indeed holding the class as a value. But, that didn't make sense either.
So what is really going on?
EDIT: modified code with output to prove that the object is not dead, as might be suggested by some answers.
2nd EDIT: what this comes down to as I've gone through some开发者_开发技巧 more code is this:
public void Dispose( )
{
Dispose(true);
GC.SuppressFinalize(this);
}
private void Dispose(bool dispose)
{
if (!isDisposed)
{
if (dispose)
{
// clean up managed objects
}
// clean up unmanaged objects
isDisposed = true;
}
}
~DisposableClass( )
{ Dispose(false); }
Stepping through the code (had a breakpoint at private void Dispose(bool dispose)
), where false
is passed to the method, it becomes imperative that resources are properly disposed of here. Regardless, the class is still alive, but you are definitely setting yourself up for exceptions. Answers made me more curious...
Disposing an object does not destroy it; it simply tells it to clean up any unmanaged resources it uses as they are no longer needed. In your example, you're creating a disposable object, assigning to a dictionary, and then just telling it to remove some resources.
The correct scenario for the using
statement is when you want to initialize a resource, do something with it, and then destroy it and forget about it; for example:
using (var stream = new FileStream("some-file.txt"))
using (var reader = new StreamReader(stream))
{
Console.Write(reader.ReadToEnd());
}
If you want to retain the object after you've used it, you shouldn't be disposing it, and hence a using
statement should not be used.
You should not be using a using
block in this case, since you need the object after the block has finished. It is only to be used when there is a clear starting and ending point of the lifetime of the object.
It's important to remember that IDisposable, while a slightly special interface, is an interface nonetheless. When the using block exits, it calls Dispose() on your object. Nothing more. Your reference is still valid and, if your Dispose method does nothing, your object will be completely unaffected. If you don't keep track the disposal and explicitly throw exceptions, then you won't get any exceptions after that point because there is no inherent disposed state in .NET.
The IDisposable
interface indicates that a type manages some kind of resource. The Dispose
method exists to allow you to dispose of the resources used by an instance without having to wait for garbage-collection to take place and the resources to be freed by a finalizer.
In your example, the dictionary is still containing a reference to the disposable class, but the instance will have been disposed at the end of the using
block. Subsequent attempts to call methods on the instance will now likely throw ObjectDisposedException
or InvalidOperationException
, to indicate the instance is no longer in a "working" state.
Disposing an IDisposable
is not to be confused with releasing the memory occupied the instance, or invoking any garbage-collection routines on it. The instance is tracked and managed by the garbage-collector like any other, only to be released when the garbage-collector decides it.
精彩评论