Чи все ще визивається Dispose, коли виняток кидається всередині використовуваного оператора?


103

У наведеному нижче прикладі, чи зв’язок закриється та розпоряджається, коли викидається виняток, якщо він знаходиться в usingоператорі?

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

Я знаю, що цей код нижче переконається, що він робить, але мені цікаво, як це використовує оператор.

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, що використовує документацію, також підтверджує цю відповідь: Оператор, що використовує, забезпечує виклик Dispose, навіть якщо виняток виникає під час виклику методів на об'єкті. Ви можете досягти того ж результату, помістивши об'єкт всередину спробу блоку, а потім викликаючи Dispose в остаточному блоці; насправді, саме так компілятор перекладає використовуючий оператор.
широкосмуговий

20

Ось як рефлектор декодує ІЛ, генерований вашим кодом:

приватний статичний недійсний Main (string [] args)
{
    SqlConnection conn = новий SqlConnection ("...");
    спробуйте
    {
        conn.Open ();
        DoStuff ();
    }
    нарешті
    {
        if (conn! = null)
        {
            conn.Dispose ();
        }
    }
}

Тож відповідь "так", вона закриє з'єднання, якщо

DoStuff ()
кидає виняток.


Додати, якщо conn.Open () кидає виняток. : D
Джефф Йейтс

Так, звісно. Якщо все, що є в блоці ПІСЛЯ, за допомогою пункту використання викидає виняток, з'єднання буде закрито. Єдиний спосіб остаточного блоку не буде виконаний, якщо "новий 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();
    }
}

Це відповідає на питання ОП ??
Joey Phillips

Так. Відповідь - ні. Dispose () не викликається у доданому коді. Крім того, виняток, який кидається, не обробляється, і програма вибухає.
Чад

Ви повинні переглядати неправильний файл. "Dispose ()" записується у ваш тимчасовий файл. Ніхто не стверджує, що блок-блок використовує виняток. Спробуйте запустити це без налагоджувача.
LarsTech

Я запустив цей самий той самий код, і він викликає Dispose (). Ви впевнені, що ваша відповідь правильна?
Dnomyar96
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.