2

Okay, I've searched "similar" topics but still haven't come across any answer to what I'm going to ask here.

I have a function that creates multiple sql objects under the System.Data.SqlClient namespace. I've read that the using statement disposes of an object after the using block but the variables declared are readonly. My function reuses some of these variables, so I can't really declare them within a using statement.

Here is the body of my function for clarity. Should I call Dispose on the other objects (command, transaction, reader, etc) or will using recursively dispose of them through the connection object? How should I dispose these objects?

I'm still new to C# (I come from C/C++ background) so please forgive me if the question sounds very ignorant.

public string SignIn(string userId, string password)
{
     SqlCommand sqlCommand = null;
     SqlTransaction sqlTransaction = null;
     string sessionId = "";

     using(SqlConnection sqlConnection = new SqlConnection Properties.Settings.Default.SessionManagerDBConnectionString))
     {
          try
          {
               sqlConnection.Open();

               sqlCommand = sqlConnection.CreateCommand();
               sqlCommand.CommandText = "GetUserByUserIdPassword";
               sqlCommand.CommandTimeout = 30;
               sqlCommand.CommandType = CommandType.StoredProcedure;
               SqlParameter parameterUserId = sqlCommand.Parameters.Add("@UserId", SqlDbType.NVarChar, 32);
               parameterUserId.Value = userId;
               SqlParameter parameterPassword = sqlCommand.Parameters.Add("@Password", SqlDbType.NChar, 64);
               parameterPassword.Value = this.GetSHA256Hash(password);
               sqlTransaction = sqlConnection.BeginTransaction("SampleTransaction");

               // more database activity, execute command, store results in datareader
               sqlTransaction.Commit();
               sqlConnection.Close();
          }
          catch (SqlException ex)
          {
               if(sqlTransaction != null)
                    sqlTransaction.Rollback();
               MessageBox.Show(ex.Number + ":" + ex.Message, ex.Server + ":" + ex.Source, MessageBoxButtons.OK, MessageBoxIcon.Error);
          }
     }
     return sessionId;
}

I tried to search for similar questions again and found some closer answers.

Is SqlCommand.Dispose() required if associated SqlConnection will be disposed?

Does SqlCommand.Dispose close the connection?

I suppose I should add a finally clause to my try-catch and call several Dispose methods there for all the sql objects I've created. I hope that suffices or is there a recommended style of doing this?

finally
{
     if(sqlCommand != null)
          sqlCommand.Dispose();
     if(sqlTransaction != null)
          sqlTransaction.Dispose();
     ...
}

I tried putting a using statement within the try-catch block for one of the sqlCommand objects, but if that part of the code aborts when an exception is thrown, the execution jumps down to the catch portion. The using does not dispose that sqlCommand object.

try
{
     ...
     using(sqlCommand = sqlConnection.CreateCommand())
     {
          sqlCommand.CommandText = "GetUserByUserIdPassword2";
          sqlCommand.CommandTimeout = 30;
          sqlCommand.CommandType = CommandType.StoredProcedure;
          SqlParameter parameterUserId = sqlCommand.Parameters.Add("@UserId", SqlDbType.NVarChar, 32);
          parameterUserId.Value = userId;
          SqlParameter parameterPassword = sqlCommand.Parameters.Add("@Password", SqlDbType.NChar, 64);
          parameterPassword.Value = this.GetSHA256Hash(password);

          SqlDataReader reader = sqlCommand.ExecuteReader(CommandBehavior.SingleRow);
          // throws exception, no stored procedure "GetUserByUserIdPassword2"
     }
     ...
}
catch() {}

// sqlCommand still accessible at this point because using above was "aborted".
Community
  • 1
  • 1
kerafill
  • 274
  • 1
  • 4
  • 14
  • Please include all relevant code, for example: `I have a function that creates multiple sql objects under the System.Data.SqlClient namespace`. Addtionally, the `using` statement will only dispose of the object in which you have referenced in the statement. Is safe to assume that anytime any class derives from `IDisposable` you should use the `using` statement (there are a few exceptions). – Erik Philips May 04 '14 at 16:24
  • That is all the code I have written so far. It's just a stub I'm experimenting with that uses these sql objects. Prior to the using statement is the local declaration of sqlCommand and sqlTransaction both initialized to null. "//more database activity" is still some code I'm playing with that basically creates a datareader to access the result returned by sqlCommand procedure. – kerafill May 04 '14 at 16:54
  • The sqlConnection is handled properly. The Command and Transaction are not exception-safe, we can't say for the DataReader. – H H May 04 '14 at 17:53
  • 1
    But you should really worry about the "My function reuses some of these" part, that sounds like a really bad design. – H H May 04 '14 at 17:54
  • @HenkHolterman Yes, I think I will do as pip says below, and not reuse the variables but declare separate ones. The function above still has more command objects. The code is ported from my old C program which further checks if the user is already signed in (so it fetches more data if that first command succeeded in returning a result)... so and so forth, more "sign-in" checks. But I don't know much about C# yet, and if I employ multiple using statements inside the try-catch block, and one of them throws an exception, the execution will jump down to the catch block. – kerafill May 04 '14 at 21:57
  • Will that inner using statement be aborted and not call the Dispose method for that variable anymore? – kerafill May 04 '14 at 21:58
  • http://msdn.microsoft.com/en-us/library/yh598w02.aspx – Andy May 05 '14 at 00:18
  • No, the most fundamental task of `using(){}` is to always cleanup, even when an exception occurs. – H H May 05 '14 at 06:44
  • @HenkHolterman Thanks.. the documentation doesn't really explain much on more complex scenarios on the use of `using`. Like in the case where an exception occurs. – kerafill May 05 '14 at 14:11
  • Yes they do. `using()` is always explained in terms of exceptions and cleanup. – H H May 05 '14 at 14:28
  • Okay, my bad. I re-read the link Andy posted above and it does say the case about thrown exceptions but in one sentence only in a paragraph. That was easy to overlook. >_ – kerafill May 06 '14 at 05:41

4 Answers4

2

If the object implements IDisposable, then use using. If you need to create a new SqlCommand for some reason then finish one using block and start a new one. Or nest them if you still need access to the first SqlCommand.
You can reuse SqlCommand objects, as long as you haven't got a datareader still open from the command. So, you could create a SqlCommand, set all its properties and execute it, then reset all its properties and execute it again and so on. This does save slightly on the costs of memory allocation, but I think it also reduces the clarity of the code, so it is something I would only do if profiling proved it necessary.

pipTheGeek
  • 2,703
  • 17
  • 16
  • I thought about having multiple using statements. But in the code example, they would all be inside the try-catch block. Will the Dispose method still be called for that inner using statement if in the case where an error was thrown and the execution would jump down to the catch portion? – kerafill May 04 '14 at 21:47
  • Simple answer is Yes. – pipTheGeek May 14 '14 at 07:22
  • There are a few circumstances where using may not call dispose. OutOfMemory errors, someone using task manager to kill your process. For normal code though these are generally not important because the process is already dying and the resources will then get freed. – pipTheGeek May 14 '14 at 07:24
1

will using recursively dispose of them through the connection object

Of course, using knows nothing about SqlConnections or other ADO.NET objects. All it knows is to call Dispose. Whatever the object being disposed does is what happens.

It happens to be the case that disposing a SqlConnection also disposes of the resources of all readers and commands associated with the connection. You only need to dispose the connection.

I don't know whether this is documented on MSDN but I know it from decompiling the assemblies. For compatibility reasons they can never change this behavior so it is safe to rely on it.

In general, you must call dispose on any object implementing IDisposable. Exception to this rule is when you know for sure that it is safe to not call Dispose. Like in this case.

usr
  • 168,620
  • 35
  • 240
  • 369
  • I'm not sure that disposing the connection is enough. It was in .NET 1.1 days, but we had problems with a web site where we had missed disposing some of the command objects and not disposing the command objects prevented the connection from closing or being returned to the pool and it eventually bought down the database server. (It was VERY old and Oracle on Unix) – pipTheGeek May 04 '14 at 21:02
  • The SqlCommand class is the class to be absolutely sure about. The SqlDataReader class is a questionable case. The .NET 4.5 code is so complex that I couldn't re-verify my statements quickly. But the command truly does not a lot. – usr May 04 '14 at 21:24
1

I think I found the answer!

Even though the sqlCommand object was still accessible in the bottom parts of the code when a nested using statement was skipped by a thrown exception, sqlCommand is still disposed later on. I tested this by actually assigning a function to the disposed event of said sqlCommand object.

The code here is slightly different than above because of the transaction object requirement. But the logic is essentially the same.

try
{
       using(sqlCommand = new SqlCommand("GetUserByUserIdPassword2", sqlConnection, sqlTransaction))
       {
              sqlCommand.CommandTimeout = 15;
              sqlCommand.CommandType = CommandType.StoredProcedure;
              SqlParameter parameterUserId = sqlCommand.Parameters.Add("@UserId", SqlDbType.NVarChar, 32);
              parameterUserId.Value = userId;
              SqlParameter parameterPassword = sqlCommand.Parameters.Add("@Password", SqlDbType.NChar, 64);
              parameterPassword.Value = this.GetSHA256Hash(password);

              sqlCommand.Disposed += new System.EventHandler(this.sqlCommand_Disposed);

              SqlDataReader sqlDataReader = sqlCommand.ExecuteReader(CommandBehavior.SingleRow);
              // exception thrown, no sored proc "GetUserByUserIdPassword2"
              sqlDataReader.Close();
       }
}
catch(...) {}

...

private void sqlCommand_Disposed(object sender, EventArgs e)
{
     MessageBox.Show("sqlCommand has been disposed");
}

So, basically, even if a nested using statement is "aborted" by a thrown exception within the try block, and execution is skipped down to the catch block, the Dispose method is still called for that object after the function exits (or when the variable goes out of scope).

I presume this behavior is the same for any number of nested using statements.

kerafill
  • 274
  • 1
  • 4
  • 14
  • 1
    The reason it works is because a using statement is basically a `try {} finally {}`, where the `Dispose()` method is called inside the `finally`. Nested finally blocks all execute as the exception logically passes from one nested try block to the next one up. This is why you are getting the behavior you are getting. – siride May 05 '14 at 01:03
  • Oh okay. I didn't know the finally block would still run even if the using statement block was skipped. Yes, you're explanation is correct, because the disposed event is executed before the exception is caught when it was thrown from within the using block. (Example above displays the dialog box for disposed event before the dialog box in the catch block.) – kerafill May 05 '14 at 01:25
-1

in CSharp, using is a special keyword which have different acts in code..

if you put using to top of the codepage then using acts as c++ ' s Include or VB (and some other script langs') Import

if you write a "using" which follows by a paranthesis then it acts like an alias of Dispose() method of CSharp.. or Destructor tilda of c++ or free() method of plain c..

About SQL Connection.. Best way is first Close() the connection (so with this, connection is still alive -actually just ready to use- but null.. return to wait new order in connection pool.. ) and then dispose if you need..

if you have still problems and suspected that calling the Dispose() method not enough to free the resources

then you can use Garbage Collector's Collect() static method to force the garbage collection But not so much recommended by Microsoft because of face with accidental garbage collection problems (i.e. you collect the form but need some variable from that form )

in example of usage :

public void Dispose (bool ForceToCollect )
{
   if (ForceToCollect) 
               GC.Collect (0, GCCollectionMode.Forced );
}

In Gc.Collect() method you can set which group of data memory freed with first option where is int..if you plan to free resources of the last group - means last created group of items, as an example last created form instance and its all child controls - then int should be 0; the one which is 1 before the last created then should be 1 and so on..

Hope this helps..

sihirbazzz
  • 708
  • 4
  • 20
  • Using statement and using directive are two different things. You don't need to call close and then dispose, close actually calls dispose and you shouldn't try to dispose an object twice. Garbage collection will not call dispose, it will try to call finalizers if the class has one, but typically finalizes only deal with unmanaged resources. – Andy May 05 '14 at 00:17
  • @Andy I didn't see any knowledge that saying "they are the same" in my explanation..But in as aside of any Talkative Language (such as English, French or German) both are the same cause they share the same characters..As OP says that "He/She is New in C#" so remind this usage difference is a good point i guess..In a normal object You are right no need to call dispose after calling a Close method..But this is SqlConnection..In DotNet when you call Close on a SqlConnection object no Finalize all resources..SqlConnection will empty and return to Connection pool like newly initialized – sihirbazzz May 05 '14 at 09:13
  • @Andy And i didn't say that "Garbage Collection calls the Dispose() method" Garbage Collection is as its name is a collection which controls the objects created and in usage of the application..Garbage Collection doesn't call Dispose method cause Dispose method signs / warns / declares that object is ready for finalize with using the internal methods of Garbage collection..If you can check, then you will see that GC is a tree-like collection..And when it collects it calls the method in native c named free() { or may be in c++ version of free or with the needs of runtime can call union() } – sihirbazzz May 05 '14 at 09:25
  • @Andy in one of my "Fully Managed Winforms" projects i use the GC.Collect() with forced option because of my needs..Reasonability to memory usage and other restrictions some like security { think on that please..almost 500 persons + 50 managers+ all their work hours, like hourly salary there are 8 different restrictions, holidays, illnesses etc, etc..for a monthly report there should be iteration on these totally more than 120.000..It was a Genetic Algorithm..1 month can scalable with a low end pc..but what if the user need more than 1 month report ? } i needed to use and works perfect ;) – sihirbazzz May 05 '14 at 09:39
  • @Andy Finally my dear friend, i guess you couldn't catch my point while reading my answer..It's not a critic, don't misunderstand me please..Probably you were so busy with your business and while reading / thinking fast on this, missed the points which i tried to inject to OP on behind-scenes.. – sihirbazzz May 05 '14 at 09:47