Вызывается ли Dispose при возникновении исключения внутри оператора using?

103

В приведенном ниже примере соединение будет закрыто и удалено при возникновении исключения, если оно находится внутри usingоператора?

using (var conn = new SqlConnection("..."))
{
    conn.Open();
    // stuff happens here and exception is thrown...
}

Я знаю, что приведенный ниже код гарантирует, что это так, но мне любопытно, как это делает оператор using.

var conn;
try
{
    conn = new SqlConnection("...");
    conn.Open();
    // stuff happens here and exception is thrown...
}
// catch it or let it bubble up
finally
{
    conn.Dispose();
}

Связанный:

Как правильно обеспечить закрытие SQL-соединения при возникновении исключения?

Брайан Ким
источник

Ответы:

112

Да, usingваш код будет заключен в блок try / finally, в котором finallyчасть будет вызывать, Dispose()если она существует. Однако он не будет вызывать Close()напрямую, поскольку проверяет только IDisposableреализуемый интерфейс и, следовательно, Dispose()метод.

Смотрите также:

Джефф Йейтс
источник
5
Просто чтобы указать на классы соединения, если вы отразите их, вы увидите, что Dispose () действительно внутренне вызывает Close (). Если он в состоянии, то может.
Крис Марисич,
2
Вы правы, это так. Однако я намеренно не упоминал об этом, поскольку не хотел никого вводить в заблуждение, думая, что это как-то связано с IDisposable или связанным с ним шаблоном. Тот факт, что эта конкретная реализация вызывает Close (), является деталью реализации, а не шаблоном.
Джефф Йейтс,
3
MSDN с использованием документации также подтверждает этот ответ: оператор using гарантирует, что Dispose вызывается, даже если во время вызова методов объекта возникает исключение. Вы можете достичь того же результата, поместив объект в блок try и затем вызвав Dispose в блоке finally; Фактически, именно так компилятор переводит оператор using.
широкополосный
20

Вот как рефлектор декодирует IL, сгенерированный вашим кодом:

private static void Main (строка [] аргументы)
{
    SqlConnection conn = новый SqlConnection ("...");
    пытаться
    {
        conn.Open ();
        DoStuff ();
    }
    Ну наконец то
    {
        если (соед! = ноль)
        {
            conn.Dispose ();
        }
    }
}

Итак, ответ - да, он закроет соединение, если

DoStuff ()
выдает исключение.

Флорин Сабау
источник
Добавить, если conn.Open () вызывает исключение. : D
Джефф Йейтс
Да, конечно. Если все, что находится в блоке ПОСЛЕ предложения using, вызывает исключение, соединение будет закрыто. Единственный способ, которым блок finally не будет выполнен, - это выбросить «new SqlConnection (...)», но в этом случае у вас не будет действительного открытого соединения, которое нужно закрыть. Так что все в порядке.
Флорин Сабау,
-1

Dispose () не вызывается в этом коде.

class Program {
    static void Main(string[] args) {
        using (SomeClass sc = new SomeClass())
        {
            string str = sc.DoSomething();
            sc.BlowUp();
        }
    }
}

public class SomeClass : IDisposable {
    private System.IO.StreamWriter wtr = null;

    public SomeClass() {
        string path = System.IO.Path.GetTempFileName();
        this.wtr = new System.IO.StreamWriter(path);
        this.wtr.WriteLine("SomeClass()");
    }

    public void BlowUp() {
        this.wtr.WriteLine("BlowUp()");
        throw new Exception("An exception was thrown.");
    }

    public string DoSomething() {
        this.wtr.WriteLine("DoSomething()");
        return "Did something.";
    }

    public void Dispose() {
        this.wtr.WriteLine("Dispose()");
        this.wtr.Dispose();
    }
}
Чад
источник
Это ответ на вопрос OP ??
Джои Филлипс
Да. Ответ - нет. Dispose () не вызывается в прилагаемом коде. Более того, возникшее исключение не обрабатывается, и программа взрывается.
Чад
Вы, должно быть, смотрите не в том файле. «Dispose ()» записывается в ваш временный файл. Никто не утверждает, что блок using обработает исключение. Попробуйте запустить это без отладчика.
LarsTech
Я запустил тот же самый код, и он вызывает Dispose (). Вы уверены, что ваш ответ правильный?
Dnomyar96