Fog Creek Software
Discussion Board




Welcome! and rules

Joel on Software

2 questions on ADO.NET and Dispose

1st question:

p.65 of David Sceppa's Microsoft ADO.NET says, "As a general rule, if an object exposes a dispose method, you should call it when you want to release the object's resources."

Let's say my code instantiates the following class called Sample:

public class Sample {
  public IDbConnection cn;
  public IDbDataAdapter da1;
  public IDbDataAdapter da2;
  public IDbDataAdapter da3;
  public DataSet ds;

  public Sample(string cnString) {
  // Code to set up cn and all the command objects of da1, da2, da3
  // which all use the cn connection
  ...
 
  da1.fill(ds,"tbl1");
  da2.fill(ds,"tbl2");
  da3.fill(ds,"tbl3");
 
  // manipulate ds
  ...

  da1.update(ds);
  da2.update(ds);
  da3.update(ds);
  }
}

When the client code is done with "Sample," should it (1) call the dispose method on all of the members in "Sample," (2) call the dispose on just the connection member, or (3) forget about the dispose method and let GC take care of it.

2nd question:

p.67 has this code sample:
using (OleDbCommand cmd = cn.CreateCommand() {
...
}
He likes that this calls the cmd's Dispose method at the end of the using block.

Why bother disposing a command object?  Isn't the connection the object which uses resources?

Charles Reich
Friday, February 04, 2005

1. No
2. Dunno
3. Yes

Mike Drips
Friday, February 04, 2005

If a class implements the IDisposable interface, then you should dispose the object as soon as you're done with it. Don't try to individually measure why they added that interface - they did, so presume that they had a reason.

Not only will it free unmanaged resources immediately, if any, good classes will remove themselves from the finalization queue (otherwise the object hangs around longer than it should, taking two garbage collections to actually be freed) which is important for performance.

Personally I think the whole using/dispose thing is a massive, unelegant hack. Managed C++ in VS.NET 2005 now includes so-called "stack" objects which automatically dispose once they're out of scope.

Dennis Forbes
Friday, February 04, 2005

1. A better approach is for your Sample class to implement IDisposable.  Look at MSDN for samples of a pattern to do this.  Your Dispose method should call Dispose on the relevant fields.  If you run FxCop on the assembly containing Sample, it will warn you that classes with IDisposable fields should implement IDisposable.

In this case, the client app would use the "using" construct (or try/finally in VB):
using (Sample sample = new Sample(connectionString)
{
  ...
} // Sample's Dispose method is called on exiting the using block.

Or reconsider your design, and don't keep a connection as a field of your class - mostly you should open and close connections as needed, so methods of the Sample class could perhaps open and close a connection.

2.  In this scenario, the connection is the resource to be freed, so it's sufficient to call Dispose (or Close) on the connection object.  OleDbCommand has a constructor which takes a connection string argument - in this case, the OleDBCommand object "owns" the connection, which is why it implements IDisposable.

Joe
Friday, February 04, 2005

Do people follow the following guideline?

If your class is going to have as a member any class that implements IDisposable, then your class should also implement IDisposable.

In particular, your class's Dispose method should call the Dispose method on each of its members (and also its own base class Dispose method, if applicable).

Charles Reich
Friday, February 04, 2005

> Do people follow the following guideline? ...

Yes.

Christopher Wells
Friday, February 04, 2005

Okay but I still wonder w.r.t. the above example:

Should we bother calling Dispose on any of those resources at all or should we let GC handle that?

Sheeshers
Wednesday, February 09, 2005

GC frees managed memory ... it doesn't free anything else.

For example I might have a class which does this:

public class BombTimer : IDispose
{
  Network network = new Network();
  public BombTimer()
  {
    network.SendMessage("Start ticking");
  }
  public void Dispose()
  {
    network.SendMessage("Stop ticking");
  }
}

The "network.SendMessage("Stop ticking");" statement cannot be invoked by the GC (which doesn't for example keep track of what messages have been sent using the Network class).

Dispose is used for "unmanaged" resources ... for example resources that are allocated by the (unmanaged) O/S instead of by the (managed) .NET framework

Christopher Wells
Thursday, February 10, 2005

*  Recent Topics

*  Fog Creek Home