views:

2287

answers:

8

I have an sqlConnection manager class like so:

public class SQLConn {
  public string connStr = System.Configuration.ConfigurationSettings.AppSettings["ConnectionString"];

  private SqlConnection sqlConn;

  public SqlConnection Connection()
  {
      sqlConn = new SqlConnection(connStr);

      return sqlConn;
  }

  public void Open()
  {
        sqlConn .Open();
  }
}

If I use a function with the 'using' statement like:

var conn = new SQLConn();

using (conn.Connection()) 
{ 
    String query = "Select * from table";
    objSql = new SqlCommand(query, conn.Connection());      

    conn.Open(); 
    DoSomething(); 
}

Does the using statement dispose of the connection automatically since conn.Connection() returns a SqlConnection object? Or, do I have to implement IDisposable and a custom Dispose method on the SqlConn class?

Is this even a good way at all? I'm working with legacy code and I'm not able to use an ORM yet but is there a way to simplify this existing pattern to manage/create SQL connections?

A: 

No you do not, as long as the returned object is IDisposable.

The returned object needs not to implement IDisposable, but then the using block would serve no purpose.

leppie
The final type of the expression *does* need to implement IDisposable: Error 1 'Bar': type used in a using statement must be implicitly convertible to 'System.IDisposable
Marc Gravell
Hmmm, interesting, is that changed behaviour from previous versions of the compiler, or have I just miss understood it all along?
leppie
I'm not aware of a change (but I haven't looked at the 1.2 spec lately).Are you perhaps thinking of `foreach`? where the enumerator *might* be disposable (and if so, is disposed), but doesn't have to be? Or perhaps the fact that the returned value is allowed to be null?
Marc Gravell
In fact, I doubt it changed - since that would clearly be a breaking change that stopped some existing code from compiling; the C# team try very hard to avoid that...
Marc Gravell
You know I am probably thinking of foreach :) Damned reflector hiding all the details makes you forget!
leppie
+9  A: 

The using statement will look at the final type of the expression - i.e. whatever is returned from .Connection(); if this returns something that is IDisposable, then you're OK.

The compiler will tell you if you get it wrong ;-p (it won't let you use using on something that isn't IDisposable).

You should probably watch out for where you are creating two connections:

using (var c = conn.Connection()) // <==edit
{ 
    String query = "Select * from table";
    objSql = new SqlCommand(query, c); // <==edit

    c.Open(); 
    DoSomething(); 
}

and possibly:

public SqlConnection Connection()
{
  if(sqlConn == null) sqlConn = new SqlConnection(connStr); // <== edit
  return sqlConn;
}
Marc Gravell
A: 

From MSDN:

The object provided to the using statement must implement the IDisposable interface.

You do not have to call Dispose() though, the using statement implicitly does this for you.

annakata
+5  A: 

It will work but after the using {} you will be left with a sqlConn that internally holds a Disposed SlConnection. Not a really useful situation

Henk Holterman
+1  A: 

Your code is wrong!

shoudl be something like this:

Dim conn as New SQLConn();
Dim sqlConnection New SQLConnection();

sqlConnection = conn.Connection();

using (sqlConnection) 
{ 
    String query = "Select * from table";
    objSql = new SqlCommand(query, sqlConnection);      

    conn.Open(); 
    DoSomething(); 
}

That way the using statement will dispose the connection at the end.

Pavel Nikolov
Why do you create two SqlConnections? At least one will not be disposed
Ruben
+1 The problem is not with writing `using (conn.Connection())`, but by the fact that the `Connection()` method creates a new object every time it is being called, and in the original post, the connection which is under the "using" is not a different instance than the connection actually being used inside the block.
Noam Gal
You probably don't need the "New SQLConnection", then
Marc Gravell
Yes we don't need new SqlConnection - sorry for that (I use C# only and don't understand VB at all)@Noam Gal - My point was that the provided code is useless, because the SQLConn class doesn't return a single SqlConnection instance. So in the code provided in the question we have one connection (which is disposed by the using statement) and another which is used by the code and is not disposed at the end...
Pavel Nikolov
A: 

It seems the connection will be closed properly, but this is not recommended:

You can instantiate the resource object and then pass the variable to the using statement, but this is not a best practice. In this case, the object remains in scope after control leaves the using block even though it will probably no longer have access to its unmanaged resources. In other words, it will no longer be fully initialized. If you try to use the object outside the using block, you risk causing an exception to be thrown. For this reason, it is generally better to instantiate the object in the using statement and limit its scope to the using block.

http://msdn.microsoft.com/en-us/library/yh598w02.aspx

Alexander Prokofyev
+1  A: 

to answer your headline question, you must implement IDisposable in the class whose object you're using with "using". Otherwise, you'll get a compile-time error.

Then, yes, "using" will dispose your SqlConnection at the end of the block. Think of "using" as a "try-finally": there is an implicit call to Dispose() in the "finally" block.

Finally, cleaner code would be:

using( SqlConnection = new SqlConnection( connStr ) {
    // do something
}

At least readers of your code won't have to make the mental effort to realize as Hank Holterman pointed out that your SQLConn object holds a reference to a disposed connection.

azheglov
A: 

Here's a nice reference.

Antwan