SqlParameter已经被另一个SqlParameterCollection包含了 – 是否使用(){}作弊?

如下所示,使用using(){} (sic)块,并假定cmd1没有超出第一个using(){}块的范围,为什么第二个块会抛出一个exception,消息SqlParameter是已经包含另一个SqlParameterCollection ? 这是否意味着资源和/或句柄(包括连接到cmd1的参数(SqlParameterCollection))在其末尾被销毁时不会被释放?

using (var conn = new SqlConnection("Data Source=.;Initial Catalog=Test;Integrated Security=True")) { var parameters = new SqlParameter[] { new SqlParameter("@ProductId", SqlDbType.Int ) }; using(var cmd1 = new SqlCommand("SELECT ProductName FROM Products WHERE ProductId = @ProductId")) { foreach (var parameter in parameters) { cmd1.Parameters.Add(parameter); } // cmd1.Parameters.Clear(); // uncomment to save your skin! } using (var cmd2 = new SqlCommand("SELECT Review FROM ProductReviews WHERE ProductId = @ProductId")) { foreach (var parameter in parameters) { cmd2.Parameters.Add(parameter); } } } 

注意:在第一个using(){}块的最后一个大括号之前执行cmd1.Parameters.Clear()将会使您免于exception(并且可能会感到尴尬)。

如果您需要重现您可以使用以下脚本来创build对象:

 CREATE TABLE Products( ProductId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED, ProductName nvarchar(32) NOT NULL) GO CREATE TABLE ProductReviews( ReviewId int IDENTITY(1,1) NOT NULL PRIMARY KEY CLUSTERED, ProductId int NOT NULL, Review nvarchar(128) NOT NULL) GO 

我怀疑SqlParameter “知道”它是哪个命令的一部分,并且该命令在处置命令时不会被清除,而是在您调用command.Parameters.Clear()清除。

我个人认为,我会避免重用的对象,但这取决于你:)

使用块不能确保对象被“销毁”,只需调用Dispose()方法即可。 实际上做的是具体实现,在这种情况下显然不会清空收集。 这个想法是确保不被垃圾收集器清理的非托pipe资源正确处置。 由于参数集合不是一个非托pipe资源,所以并不完全令人惊讶,它不会被dispose方法清除。

using定义了一个范围,并为我们所喜爱的自动调用Dispose()

如果另一个对象有引用,那么引用超出范围的引用不会使对象本身“消失”,在这种情况下,引用cmd1 parameters就是这种情况。

添加cmd.Parameters.Clear(); 执行后应该没事的。

我遇到这个exception,因为我没有实例化一个参数对象。 我以为是抱怨两个程序有同名的参数。 它抱怨两次添加相同的参数。

  Dim aParm As New SqlParameter() aParm.ParameterName = "NAR_ID" : aParm.Value = hfCurrentNAR_ID.Value m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm) aParm = New SqlParameter Dim tbxDriveFile As TextBox = gvNetworkFileAccess.Rows(index).FindControl("tbxDriveFolderFile") aParm.ParameterName = "DriveFolderFile" : aParm.Value = tbxDriveFile.Text m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm) **aParm = New SqlParameter()** <--This line was missing. Dim aDDL As DropDownList = gvNetworkFileAccess.Rows(index).FindControl("ddlFileAccess") aParm.ParameterName = "AccessGranted" : aParm.Value = aDDL.Text **m_daNetworkAccess.UpdateCommand.Parameters.Add(aParm)** <-- The error occurred here.