Вызывается ли 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

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.