问题
I have following code that uses SqlTransaction. I have called dispose in catch and finally blocks.. But I have not checked whether it is already disposed before calling Dispose(). How can we check whether the SqlTransaction is already disposed before calling Dispose()?
I have referred MSDN:SqlTransaction.Dispose Method. But that does not cover my question.
Also referred http://msdn.microsoft.com/en-us/library/system.data.sqlclient.sqltransaction.dispose(v=vs.100).aspx
Note: I already know that TransactionScope has advantages over SqlTransaction. But I am trying to understand the SqlTransaction’s dispose.
CODE
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
transaction = connection.BeginTransaction();
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other code
//Commit
transaction.Commit();
}
catch
{
//Rollback
if (transaction != null)
{
transaction.Rollback();
transaction.Dispose();
}
//Throw exception
throw;
}
finally
{
if (transaction != null)
{
transaction.Dispose();
}
}
回答1:
How can we check whether the SqlTransaction is already disposed before calling Dispose()?
You don't have to. Calling dispose twice won't cause you any problem.
Dispose - MSDN
If an object's Dispose method is called more than once, the object must ignore all calls after the first one. The object must not throw an exception if its Dispose method is called multiple times. Instance methods other than Dispose can throw an ObjectDisposedException when resources are already disposed.
But if you want to only call Dispose once then you can either use a boolean flag to set when the transaction is disposed or you can set it to null. Or remove the call to dispose in catch block since finally block will always be called.
Since SqlTransaction implements IDisposable, its better if you use it with using block. Something like:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
using (SqlTransaction transaction = connection.BeginTransaction())
{
try
{
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other code
//Commit
transaction.Commit();
}
catch
{
//Rollback
if (transaction != null)
{
transaction.Rollback();
}
//Throw exception
throw;
}
}
}
Since using block acts like try/finally block, and it will ensure the disposal of the transaction upon its completion (even if the exception occurs). So you don't have to manually call Dispose.
回答2:
Add transaction=null after you call dispose and then your existing tests will work.
回答3:
Why do you want to check to see whether it's been disposed already? You can avoid calling Dispose twice by simply omitting the call from your catch block:
using (SqlConnection connection = new SqlConnection(connectionString))
{
connection.Open();
SqlTransaction transaction = null;
try
{
transaction = connection.BeginTransaction();
sessionID = GetSessionIDForAssociate(connection, empID, transaction);
//Other code
//Commit
transaction.Commit();
}
catch
{
//Rollback
if (transaction != null)
{
// No need to dispose here - finally is always called
transaction.Rollback();
}
//Throw exception
throw;
}
finally
{
if (transaction != null)
{
// Always called, so no need to dispose elsewhere.
transaction.Dispose();
}
}
回答4:
Remove the .Dispose() call from catch block. Finally is ALWAYS executed, so this way you are trying two times to dispose transaction.
It does not answer "how can I know if it was already disposed" but probably solve your problem.
来源:https://stackoverflow.com/questions/14438736/how-to-check-state-before-disposing-sqltransaction