繁体   English   中英

代码分析工具

[英]Code Analysis tool

我正在使用Visual Studio的代码分析工具,它给我的警告之一是“不要多次处置对象:在方法'CycleMessages.discernScan_Reprint()'中可以多次处置对象'conn'。 System.OjectDisposedEx,您不应在对象上多次调用Dispose。Line: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;}
    }

我不处置conn(通过conn.Dispose()明确地);我只是将其关闭,并允许使用封装来丢弃conn对象-我知道我可以通过处置将其关闭,但是为什么呢?它说我要处置两次? 如果有的话,它应该警告我说“您不需要终止将要处置的对象的连接”或类似的东西。 我想念什么吗?

编辑:从引用链接上关闭...

Close方法将回滚任何未决的事务。 然后,它将连接释放到连接池,或者如果禁用了连接池,则关闭连接。

如果SqlConnection超出范围,则不会关闭它。 因此,您必须通过调用Close或Dispose显式关闭连接。 Close和Dispose在功能上是等效的。 如果连接池的值Pooling设置为true或yes,则基础连接将返回到连接池。 另一方面,如果Pooling设置为false或no,则关闭与服务器的基础连接。

我知道Close()在功能上与dispose相同,但是根据我的理解,这不是字面意思。 当我关闭对象时,它不会被丢弃。 它要么关闭,要么返回到连接池,在内部处理(再次根据我的理解)在内部调用close()方法-因此,尽管冗余,但对于为什么要明确指出它已经被处理(如果尚未被处理),我仍然感到困惑。

Dispose模式建议实现者为Dispose提供在对象上下文中有意义的同义词。 SqlConnection上的此类同义词之一是Close()

Close和Dispose在功能上是等效的。

由于您显式地调用Close() ,并且在连接的using语句结束时将调用对象的Dispose()方法,因此您实际上已两次调用了Dispose()

最好的方法是让using块为您处理它,因为即使在using块内部发生异常,它也保证可以调用Dispose() 它还将变量设置为null,以便可以尽快对其进行GC处理。


编辑以回复@alykin的问题

该文档说Close()Dispose()方法在功能上是等效的,但是@alykin已经确定了一种情况,它们实际上并没有做同样的事情。 如果我正确阅读了她的评论,它的工作原理如下:

以下作品:

SqlConnection conn = GetConnSomehow();
SqlCommand cmd = conn.CreateCommand(); 

// ...

conn.Open();

cmd.ExecuteSomething();

cmd.Close();

// ... time passes ...

conn.Open();

以下不是:

SqlConnection conn = GetConnSomehow();
SqlCommand cmd = conn.CreateCommand(); 

using ( conn ) {
    cmd.ExecuteSomething();
}

// ... time passes ...

// This won't compile, according to alykins.
conn.Open();

这表明SqlConnection对象至少在仅使用Close()时才可以重用。

带有using块的第二个示例无法编译的原因可能是,编译器知道在using块结束时conn已设置为null,因此它知道您不能在null对象引用上调用方法。

我仍然不确定这是否表明Dispose()实际上与Close()有所不同,因为不一致之处是由于using块的空语义而引起的。 值得测试的是在Dispose()但不为空之后是否可以重新打开SqlConnection。 即使是这样,我也不会依赖该行为,因为它与Microsoft在Dispose Pattern文档中设置的准则背道而驰。

另外,我不会使用不使用using块的第一个块-如果发生异常,则连接可能会泄漏,或者至少在不确定的时间内保持打开状态,直到GC看到该对象为止已泄漏并调用其终结器。

我不会依赖Close()Dispose()之间行为上的任何差异-我建议不要尝试重新打开以前关闭的SqlConnection对象。 让池管理器实际上使连接保持活动状态,即使您关闭或处置您已处理的SqlConnection对象也是如此。


有关使用语句的说明。

考虑以下代码块:

IDisposable thing = GetThing();

using ( thing ) {
   thing.DoWork();
}

该代码块与此代码块完全相同

IDisposable thing = GetThing();

try {
   thing.DoWork();
}
finally {
   thing.Dispose();
   thing = null;
}

微软认为,以下内容,其文档和分析工具被视为两个处置:

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.

忽略Close和Dispose并不会完全执行相同操作的事实。 他们不希望您依靠它,也不希望您的行为确实得到解决。

它通知您显式关闭正在尽早配置资源。 using语句将自动为您处理它。

close(); dispose(); 本质上做同样的事情,这就是为什么您收到此警告。 检查此链接以获取更多信息。

根据MSDN

Close和Dispose在功能上是等效的。

因此,调用.Close()处理该对象。 另外,由于对象位于using块中,因此编译器还会调用.Dispose() 只需两者之一。 (在这种情况下,建议使用后者。)

本质上,您只需要删除对Close()的调用,因为using块在处理对象时将为您处理该调用:

using (conn)
{
    SqlCommand cmd = new SqlCommand("usp_myproc", conn);
    cmd.CommandType = CommandType.StoredProcedure;
    using(cmd)
    {
        cmd.Parameters.Add(new SqlParameter("@param", param));
        conn.Open();
        System.Data.SqlClient.SqlDataReader dr = cmd.ExecuteReader();
        dt.Load(dr);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM