tags:

views:

278

answers:

12

I asked a question about this method:

// Save an object out to the disk
public static void SerializeObject<T>(this T toSerialize, String filename)
{
    XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
    TextWriter textWriter = new StreamWriter(filename);

    xmlSerializer.Serialize(textWriter, toSerialize);
    textWriter.Close();
}

in the response I got this as an added remark:

Make sure you always dispose disposable resources such as streams and text readers and writers. This doesn't seem to be the case in your SerializeObject method.

So, I can tell that this is going to seem super lame for someone who has been coding C# for a year or two, but why do I have to dispose it?

Is see that testWriter has a dispose method, but shouldn't garbage collection take care of that? I came from Delphi to C#. In Delphi I had to clean up everything, so this is not a case of me wanting to be lazy. I just was told that if you force freeing up the memory that your objects take then it can cause bad stuff. I was told to "Just let the garbage collector do it".

  1. So, why do I need to call dispose? (My guess is that it is because textWriter hits the disk.)
  2. Is there a list of objects I need to be careful with? (Or an easy way to know when I need to call dispose?)
+1  A: 

If you are opening a resource (such as a file, or opening a database connection) then disposing the resource will release its hold on the resource. If you don't do this then other people might not be able to connect to the database or use the file.

As a general rule of thumb....if the class implements the IDisposable interface, then you should call the Dispose() method when you are finishing it. More than likely there was a reason for them making it disposable :)

Dismissile
+2  A: 

If you are using native resources (for example file handles) then you should call Dispose() to close them soon, and not when the GC runs(which might be much later in higher gc generations). And you want to close the file since file access usually locks the file in some way.

CodeInChaos
+4  A: 

If you know you're not going to use a certain resource you can simply dispose of it yourself; you will certainly be faster than the garbage collector and will allow others to use the file or whatever you have opened faster. The easiest way would be to use your TextWriter or any other resource in a using:

using (TextWriter textWriter = new StreamWriter(filename))
{
    xmlSerializer.Serialize(textWriter, toSerialize);
}

This basically ensures the TextWriter is disposed at the end. You don't need it any more than that, anyway.

alex
probably not necessary to do both Close and Dispose
Conrad Frix
@Conrad yeah, I know. I left his code mostly as it was, just to show him that there's little he needs to change.
alex
+4  A: 

Garbage collector releases all resources, but the time when it does this is undefined. Dispose method provides a way to release unmanaged resources immediately.

Alex Farber
"Garbage collector releases all resources" Not necessarily: Imagine object Bob has subscribed to an event of a longer-lived object (e.g. it's AppDomain). The GC will never clean up Bob unless you tell him to unsubscribe from that event!
nikie
Right, GC just calls finalizer, it is class developer's responsibility to release resources in Dispose/finalizer. I was talking about using disposable .NET classes, like TextWriter from the question, which are (hopefully) written properly.
Alex Farber
+10  A: 

You are correct that for properly written code the GC will eventually clean up the native resources. The object will have a finalizer, and during finalization will free up the necessary native resources.

However when this happens is very non-deterministic. Additionally it's a bit backwards because you're using the GC which designed to handle managed memory as a means to manage native resources. This leads to interesting cases and can cause native resources to stay alive much longer than anticipated leading to situations where

  • Files are open long after they are no longer used
  • Resource handles can run out because the GC doesn't see enough memory pressure to force a collection and hence run finalizers

The using / dispose pattern adds determinism to the cleanup of native resources and removes these problems.

JaredPar
+12  A: 

The rule of thumb here is pretty simple: always call Dispose() on objects that implement IDisposable (not all objects do). You won't always know the reason why an object had to implement Dispose, but you should assume that it is there for a reason.

The easiest way to make sure you do this is through using:

using (TextWriter tw = new StreamWriter(fileName))
{
   // your code here
}

This will call Dispose() automatically at the end of the using block (it's fundamentally the same as using a try/catch/finally with the Dispose() in the finally block).

For more information on how Dispose works with garbage collection, see here.

Jon B
A: 

The garbage collector will indeed "take care of that". Sooner or later. When it gets around to calling the finalizer, after the next garbage collection.

Calling Dispose ensures that resources (like file handles) get released as soon as possible, thereby making them available for re-use by other processes in the system. Most of the time, you won't notice the difference between calling Dispose yourself and letting the garbage collector handle it. But there are times when you will. A Web crawler, for example, that creates a lot of HttpWebResponse objects, will quickly run out of connections if you don't dispose them after use. (Not that I've run into that problem ... no, not me.)

Jim Mischel
A: 

The reason to call Dispose rather than waiting for the GC is often because you are using a finite system resource which you want to release as quickly as possible so that other processes or threads can use it. For objects that have the IDisposable pattern, the "using" construct is an easy and readable way to make sure that Dispose is called.

o. nate
+1  A: 

From the TextWriter.Dispose documentation:

Note Always call Dispose before you release your last reference to the TextWriter. Otherwise, the resources it is using will not be freed until the garbage collector calls the TextWriter object's Finalize method.

From the Object.Finalize documentation:

The exact time when the finalizer executes during garbage collection is undefined. Resources are not guaranteed to be released at any specific time, unless calling a Close method or a Dispose method.

and

The Finalize method might not run to completion or might not run at all in the following exceptional circumstances:

  • Another finalizer blocks indefinitely (goes into an infinite loop, tries to obtain a lock it can never obtain and so on). Because the runtime attempts to run finalizers to completion, other finalizers might not be called if a finalizer blocks indefinitely.

  • The process terminates without giving the runtime a chance to clean up. In this case, the runtime's first notification of process termination is a DLL_PROCESS_DETACH notification.

The runtime continues to Finalize objects during shutdown only while the number of finalizable objects continues to decrease.

Wim Coenen
A: 

In generally you must dispose objects when you do not need them anymore.

Not disposing object when you finish with them will be meaning that will block access to for other processed/applications to them.

signetro
+2  A: 

Well actually you already are disposing it since the textWriter.Close Method does it.

public virtual void Close()
{
    this.Dispose(true);
    GC.SuppressFinalize(this);
}

So you could change your code to. This

public static void SerializeObject<T>(this T toSerialize, String filename)
{
    TextWriter textWriter;
    try
    {
         XmlSerializer xmlSerializer = new XmlSerializer(toSerialize.GetType());
         textWriter = new StreamWriter(filename);

          xmlSerializer.Serialize(textWriter, toSerialize);
    }
    finally
   {
       textWriter.Close();
   }

Which is pretty similar to what the using() does in the other answers.

The impact of not doing this is that if an error occurs with Serialize it would be a while before the Framework gave up its file lock (when it Processes the fReachable queue).

I know FxCop tells you when to implment IDisposable but I don't think there's any easy way to find out when you need to call Dispose other than looking at the Docs and seeing if an object implments IDisposable (or intellisense).

Conrad Frix
+1  A: 

A programmer thinking that one doesn't have to worry about disposing things because a finalizer will take care of them is like a driver thinking one doesn't have to worry about avoiding collisions because the car has an airbag. Yes, an airbag will make things more survivable, but...

supercat