Nyr*_*yra 2 c# dispose sqlconnection
我正在使用Visual Studio的代码分析工具,它给我的一个警告是"不要多次处置对象:对象'conn'可以在方法'CycleMessages.discernScan_Reprint()'中多次处理."以避免生成System.OjectDisposedEx你不应该在一个对象上多次调用Dispose.行:61
private void discernScan_Reprint()
{
try
{
DataTable dt = new DataTable();
SqlConnection conn = new SqlConnection("my constring");
using (conn)
{
SqlCommand cmd = new SqlCommand("usp_myproc", conn);
cmd.CommandType = CommandType.StoredProcedure;
using(cmd)
{
cmd.Parameters.Add(new SqlParameter("@param", param));
conn.Open();
SqlDataReader dr = cmd.ExecuteReader();
dt.Load(dr);
conn.Close(); // this is line 61
}
}
switch(dt.Rows.Count)
{
default:
throw new Exception("message");
case 1:
//do Stuff
case 0:
//do stuff
break;
}
}
catch (Exception ex) {throw;}
}
Run Code Online (Sandbox Code Playgroud)
我没有处理conn(显式通过conn.Dispose();),我只是关闭它并允许使用封装来conn对象 - 我知道我可以允许它通过处理关闭,但为什么是它说我要两次处理它?如果有的话它应该警告我说"你不需要终止对将被处置的物体的连接"或类似的东西.我错过了什么吗?
编辑:从关闭的ref链接...
Close方法回滚所有挂起的事务.然后,它会释放与连接池的连接,或者在禁用连接池时关闭连接.
和
如果SqlConnection超出范围,则不会关闭.因此,您必须通过调用Close或Dispose显式关闭连接.关闭和处置在功能上是等效的.如果连接池值Pooling设置为true或yes,则将基础连接返回到连接池.另一方面,如果Pooling设置为false或no,则关闭与服务器的基础连接.
我知道功能上的Close()与dispose相同,但这不符合我的理解.当我关闭物体时它没有被丢弃.它被关闭或返回到连接池,处理(再次从我的理解)内部调用close()方法 - 所以在冗余的时候,我仍然感到困惑,为什么它明确地说它已经被处理掉了,当它不是时.
该Dispose模式表明,实现者提供的同义词Dispose在对象的背景下才有意义.SqlConnection上的一个这样的同义词是Close():
关闭和处置在功能上是等效的.
由于您是显式调用Close(),并且在Dispose()连接using语句结束时调用了对象的方法,因此您实际上是在调用Dispose()两次.
最好的方法是让using块为你处理它,因为它保证Dispose()即使在using块内部发生异常时也会调用它.它还将变量设置为null,以便尽快进行GC.
编辑回应@ alykin的问题
文档说这些Close()和Dispose()方法在功能上是等价的,但是@alykin已经确定了一个他们实际上并没有做同样事情的场景.如果我正确地阅读她的评论,它的工作原理如下:
以下作品:
SqlConnection conn = GetConnSomehow();
SqlCommand cmd = conn.CreateCommand();
// ...
conn.Open();
cmd.ExecuteSomething();
cmd.Close();
// ... time passes ...
conn.Open();
Run Code Online (Sandbox Code Playgroud)
以下不是:
SqlConnection conn = GetConnSomehow();
SqlCommand cmd = conn.CreateCommand();
using ( conn ) {
cmd.ExecuteSomething();
}
// ... time passes ...
// This won't compile, according to alykins.
conn.Open();
Run Code Online (Sandbox Code Playgroud)
这表明SqlConnection对象可以重用,至少在他们只是Close()'d'的时候.
可能使用using块的第二个示例无法编译的原因是编译器知道conn在using块结束时已经设置为null ,因此它知道您无法在空对象引用上调用方法.
我仍然不确定这表明a Dispose()实际上与a不同Close(),因为由于使用块的语义归零而产生不协调.值得测试一下SqlConnection是否可以在它被Dispose()删除之后重新打开.即使它是,我也不会依赖于这种行为,因为它违反了微软在Dispose Pattern文档中设置的指南.
另外,我不会使用不使用using块的第一个块 - 如果发生异常,连接可能会泄漏,或者至少在非确定性的时间内保持打开状态,直到GC看到该对象为止已被泄露并调用其终结者.
我不会依赖于Close()和之间行为的任何差异Dispose()- 我建议不要尝试重新打开以前关闭的SqlConnection对象.即使你关闭或处理你交给的SqlConnection对象,让pooler句柄实际保持连接存活.
关于使用陈述的说明.
考虑以下代码块:
IDisposable thing = GetThing();
using ( thing ) {
thing.DoWork();
}
Run Code Online (Sandbox Code Playgroud)
的代码块是恰好相同块:
IDisposable thing = GetThing();
try {
thing.DoWork();
}
finally {
thing.Dispose();
thing = null;
}
Run Code Online (Sandbox Code Playgroud)
Microsoft认为,以下块,其文档及其分析工具计为两个部分:
SqlConnection conn = GetConn();
using ( conn ) {
DoWork(conn);
conn.Close(); // code analysis tools count this as one Dispose().
} // implicit conn.Dispose() from the using block, so that's two.
Run Code Online (Sandbox Code Playgroud)
忽略Close和Dispose不完全相同的事实.他们不希望你依赖它,也不应该在行为确实得到修复的情况下.