问题
According to MSDN If the IDisposable resource of the nested inner using statement contains the resource of the outer using statement, the Dispose method of the nested resource releases the contained resource.
MSDN (http://msdn.microsoft.com/en-us/library/ms182334.aspx) =>
Example Nested using statements (Using in Visual Basic) can cause violations of the CA2202 warning. If the IDisposable resource of the nested inner using statement contains the resource of the outer using statement, the Dispose method of the nested resource releases the contained resource. When this situation occurs, the Dispose method of the outer using statement attempts to dispose its resource for a second time. In the following example, a Stream object that is created in an outer using statement is released at the end of the inner using statement in the Dispose method of the StreamWriter object that contains the stream object. At the end of the outer using statement, the stream object is released a second time. The second release is a violation of CA2202.
But if i try this piece of code the code still works and returns the number count inserted into the table. Which is contradictory towards the MSDN explanation. I would expect the code to crash on the cmd.ExecuteScalar() call because the conn variable is disposed after the first inner using statement. Why is this still working and why isn't the conn variable disposed after the first inner using?
static void Main(string[] args)
{
var numbers= DoItGetIt();
}
private static int DoItGetIt()
{
using (var conn = new SqlConnection("Data Source=BestmixSql;Initial Catalog=Test;Integrated Security=True"))
{
conn.Open();
using (var cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = "INSERT INTO [Test].[dbo].[Tabel] VALUES (666)";
cmd.ExecuteNonQuery();
}
using (var cmd = new SqlCommand())
{
cmd.Connection = conn;
cmd.CommandText = "SELECT COUNT(*) FROM [Test].[dbo].[Tabel]";
var count = cmd.ExecuteScalar();
return Convert.ToInt32(count);
}
}
}
回答1:
The MSDN example you are talking to is specifically talking to the scenario where the inner object takes posession of the outer object; for example, a StreamWriter
can assume responsibility for a Stream
. In that scenario, disposing the inner object also causes the outer object to be disposed - but this is not true in the general case.
In particular, a command does not assume responsibility for disposing a connection. Interestingly, a data-reader can assume responsibility, but only via an optional flag.
Many such objects offer flags to let the caller determine whether the inner object should assume responsibility for disposing the outer object. For example, StreamWriter
also now offers a constructor-overload with a bool leaveOpen
parameter. If you pass this as true
, the StreamWriter
does not cascade the Dispose()
.
This is all implementation details of the inner object, when it is specifically written to do this. It is not a default behaviour of the using
pattern.
Side note: I would say MSDN is simply wrong here. The correct implementation is the first sample with two using
. The second example is non-intuitive, and prone to incorrect implementation. Don't use it. If necessary, use leaveOpen
to make is explicit, but frankly it usually works fine without this, if you are about to dispose it anyway.
来源:https://stackoverflow.com/questions/21783907/sqlcommand-sqlconnection-using-disposing-issue