将在“using”语句中内联创建的所有对象都将被处理掉吗?

时间:2014-02-18 20:32:39

标签: c# dispose using

这可以在其他地方回答,但经过一些搜索后,我发现在正常using上下文之外的主题上并没有找到太多内容。

我很好奇,如果using块中创建的所有对象与原始对象一样处理掉。

以下是上下文:

通常我会做这样的事情:

using (var conn = new SqlConnection(connectionString))
using (var cmd = new SqlCommand(commandText, conn))
{
    //Do everything I need to here
}

我知道此时conncmd都超出了范围,因为可爱的using关键字而被废弃。

我很好奇相同的处理规则是否适用于以下声明:

using (var cmd = new (SqlCommand(commandText, new SqlConnection(ConnectionString)))
{
   //Do everything I need here
}

SqlConnection超出范围并因为它与对象关联而被处置时,using语句中内联创建的cmd对象是否会被处置掉?

哪种语法更受欢迎?我个人认为第二个更干净,但我知道可读性也可以在这里发挥作用。

4 个答案:

答案 0 :(得分:10)

对于您的第二个代码,当流离开Dispose时,SqlConnection实例不会调用using,除非SqlCommand.Dispose()在内部执行此操作(并且不,它不会吨)。

根据规范(8.13),using (ResourceType resource = expression) statement转换为:

{
    ResourceType resource = expression;
    try {
        statement;
    }
    finally {
        if(resource != null)
            ((IDisposable)resource).Dispose();
    }
}

在您的代码中,resourceSqlCommand,而Dispose就是{{1}}。

答案 1 :(得分:4)

没有

using语句仅适用于语句中直接声明的资源;而不是初始化程序中的其他分配。

每个资源都需要单独的using语句。

答案 2 :(得分:2)

According to MSDN,此代码:

using (var temp = obj)
{
    // ...
}

转换为(包括用于限制范围的额外花括号):

{
    var temp = obj;
    try
    {
        // ...
    }
    finally
    {
        if (temp != null)
            ((IDisposable)temp).Dispose();
    }
}

如您所见,如果您将obj替换为new SqlCommand(commandText, new SqlConnection(ConnectionString)),则只会SqlCommand被正确处理。

{
    SqlCommand temp = new SqlCommand(commandText,
        new SqlConnection(ConnectionString));
    try
    {
        // ...
    }
    finally
    {
        if (temp != null)
            ((IDisposable)temp).Dispose();
    }
}

因此,SqlConnection不会被处置,除非被处置的SqlCommand这样做。但它没有,它不应该:它没有创建对象,因此它也不能破坏它。

答案 3 :(得分:2)

当然,已有答案可以正确解释这一点。这被其他人提到的规范所涵盖。

但你可以尝试一下。这是一个例子:

static class Program
{
    static void Main()
    {
        using (new DisposeMe("outer", new DisposeMe("inner", null)))
        {
            Console.WriteLine("inside using");
        }
        Console.WriteLine("after using scope");
    }
}

class DisposeMe : IDisposable
{
    public readonly string name;

    public DisposeMe(string name, object dummy)
    {
        this.name = name;
    }

    public void Dispose()
    {
        Console.WriteLine("'Dispose' was called on instance named " + name);
    }
}

输出:

inside using
'Dispose' was called on instance named outer
after using scope

(当然如果你嵌套两个using语句,就像在using (var inner = new DisposeMe("inner", null)) { using (new DisposeMe("outer", inner)) { ... } }中一样,在两个对象上调用Dispose方法。)