SqlCommand-SqlConnection使用Disposing问题

时间:2014-02-14 16:02:04

标签: c# dispose using-statement

根据MSDN如果是IDisposable资源的  嵌套的内部using语句包含外部使用的资源  声明,嵌套资源的Dispose方法释放了  包含资源。

MSDN(http://msdn.microsoft.com/en-us/library/ms182334.aspx)=>

  

示例嵌套使用语句(在Visual Basic中使用)可能导致   违反CA2202警告。如果是IDisposable资源的   嵌套的内部using语句包含外部使用的资源   声明,嵌套资源的Dispose方法释放了   包含资源。当这种情况发生时,Dispose方法   外部使用语句试图为其配置其资源   第二次。在以下示例中,创建了一个Stream对象   在外部使用语句中,在内部使用结束时释放   StreamWriter对象的Dispose方法中的语句   包含流对象。在外部使用声明的末尾,   流对象第二次释放。第二个版本是   违反CA2202。

但是,如果我尝试这段代码,代码仍然有效,并返回插入表中的数字计数。这与MSDN解释相矛盾。我希望代码在cmd.ExecuteScalar()调用时崩溃,因为conn变量在第一个内部using语句之后被释放。 为什么这仍然有效?为什么在第一个内部使用之后没有配置conn变量?

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 个答案:

答案 0 :(得分:2)

您正在与之交谈的MSDN示例专门讨论内部对象占用外部对象的场景;例如,StreamWriter可以承担Stream的责任。在那个场景中,处理内部对象也会导致外部对象被处理 - 但在一般情况下这不是真的。

特别是,命令不承担处理连接的责任。有趣的是,数据阅读器可以承担责任,但只能通过可选标志。

许多此类对象提供标记以允许调用者确定内部对象是否应承担处置外部对象的责任。例如,StreamWriter现在也提供带bool leaveOpen参数的构造函数重载。如果您将其作为true传递,则StreamWriter级联Dispose()

这是内部对象的所有实现细节,当专门编写为执行此操作时。它不是using模式的默认行为。


旁注:我会说MSDN在这里完全错了。 正确实现是第一个包含两个using的示例。第二个例子不直观,容易出错。不要使用它。如果有必要,使用leaveOpen来明确表示,但坦率地说,如果你不管怎么说它通常都可以正常使用它。