С... End With vs Использование в VB.NET

Я только что узнал, что, как и С#, VB.NET также имеет ключевое слово using.

До сих пор я думал, что этого не было (глупо от меня, я знаю...) и делал вот так:

With New OleDbConnection(MyConnectionString)
   ' Do stuff
End With

Каковы последствия этого по сравнению с выполнением этого с инструкцией using вроде этого

Using cn as New OleDBConnection(MyConnectionString)
    With cn
        ' Do stuff with cn
    End With
End using

UPDATE:

Я должен добавить, что я знаком с тем, что делает оператор using в том, что он удаляет объект при выходе из конструкции.

Однако, насколько я понимаю, конструкция With New ... будет иметь объект, помеченный как объект, готовый для сбора мусора, когда он выходит из области видимости.

Итак, мой вопрос на самом деле, единственная разница в том, что с using я сразу же выпущу память, тогда как с конструкцией With она будет выпущена всякий раз, когда GC это нравится? Или я пропущу что-то большее здесь?

Есть ли какие-либо последствия для лучшей практики? Должен ли я перейти и переписать весь код, используя With New MyDisposableObject() ... End With как Using o as New MyDisposableObject()?

Ответ 1

Используя With... End With, вы можете выполнить серию операторов на указанном объекте без указания имени объекта несколько раз.

A Использование блока ведет себя как Try... Наконец, конструкция, в которой блок Try использует ресурсы, и блок finally блокирует их.

Управляемые ресурсы утилизируются сборщиком мусора без какого-либо дополнительного кодирования с вашей стороны. Вам не нужны Использование или С. Иногда ваш код требует неуправляемых ресурсов. Вы несете ответственность за их распоряжение. Блок Использование гарантирует, что метод Dispose для объекта вызывается, когда ваш код завершается с ними.

Ответ 2

With Заявления/Блокировки

Однако, насколько я понимаю, конструкция With New... будет иметь объект, помеченный как объект, готовый для сбора мусора, когда он выходит за рамки.

Это верно и не верно. Это верно в том смысле, что все объекты "отмечены" (пуристы могут спорить с этой терминологией, но детали не актуальны), как готовые к сборке мусора, когда они выходят за рамки. Но тогда в этом смысле это также не совсем так, поскольку в отношении этого поведения нет особого ключевого слова With. Когда объект выходит из сферы действия, он имеет право на сбор мусора. Период. Это верно для области уровня метода, и это верно для области уровня блока (например, With, For, Using и т.д.).

Но не потому, что вы используете With. Причина в том, что он позволяет вам устанавливать несколько свойств последовательно на глубоко вложенном объекте. Другими словами, предположим, что у вас есть объект, на котором вы хотите установить кучу свойств, и вы получите доступ к нему следующим образом: MyClass.MemberClass.AnotherMemberClass.Items(0). Посмотреть все эти точки? Он может (теоретически) стать неэффективным для написания кода, который должен работать через эту последовательность точек снова и снова, чтобы получить доступ к одному и тому же объекту каждый раз, когда вы устанавливаете на нем свойство. Если вы знаете что-либо о C или С++ (или любом другом языке с указателями), вы можете думать о каждой из этих точек, что подразумевает разыменование указателя. Оператор With в основном проходит через всю эту косвенность только один раз, сохраняя результирующий объект во временной переменной и позволяя вам устанавливать свойства непосредственно на этот объект, хранящийся в временная переменная.

Возможно, какой-то код поможет сделать вещи более ясными. Всякий раз, когда вы видите точку, подумайте, что это может быть медленным!

Предположим, что вы начинаете со следующего кода, извлекаете объект 1 из глубоко вложенной коллекции Items и устанавливаете на нем несколько свойств. Посмотрите, сколько раз нам нужно извлекать объект, даже если он точно тот же самый объект каждый раз?

MyClass.MemberClass.AnotherMemberClass.Items(0).Color   = Blue
MyClass.MemberClass.AnotherMemberClass.Items(0).Width   = 10
MyClass.MemberClass.AnotherMemberClass.Items(0).Height  = 5
MyClass.MemberClass.AnotherMemberClass.Items(0).Shape   = Circle
MyClass.MemberClass.AnotherMemberClass.Items(0).Texture = Shiny
MyClass.MemberClass.AnotherMemberClass.Items(0).Volume  = Loud

Теперь мы модифицируем этот код для использования блока With:

With MyClass.MemberClass.AnotherMemberClass.Items(0)
    .Color   = Blue
    .Width   = 10
    .Height  = 5
    .Shape   = Circle
    .Texture = Shiny
    .Volume  = Loud
End With

Эффект здесь, однако, идентичен следующему коду:

Dim tempObj As MyObject = MyClass.MemberClass.AnotherMemberClass.Items(0)
tempObj.Color   = Blue
tempObj.Width   = 10
tempObj.Height  = 5
tempObj.Shape   = Circle
tempObj.Texture = Shiny
tempObj.Volume  = Loud

Конечно, вы не вводите новую область видимости, поэтому tempObj не выйдет за рамки (и, следовательно, будет иметь право на сбор мусора) до тех пор, пока не исчезнет область более высокого уровня, но это вряд ли будет иметь значение. Коэффициент усиления производительности (если таковой имеется) присоединяется к обоим последним двум фрагментам кода.

Настоящая победа в использовании блоков With в настоящее время - не производительность, а читаемость. Дополнительные мысли о With, возможные улучшения производительности, стилистические предложения и т.д. См. ответы на этот вопрос.

With New?

Добавление ключевого слова New в оператор With имеет тот же эффект, о котором мы только что говорили (создание локальной временной переменной для хранения объекта), за исключением того, что оно почти совершенно бессмысленно. Если вам нужно создать объект с помощью New, вы можете также объявить переменную для ее хранения. Вероятно, вам придется что-то сделать с этим объектом позже, например передать его другому методу, и вы не можете сделать это в блоке With.

Кажется, единственной целью With New является то, что она позволяет избежать явного объявления переменной, вместо этого заставить компилятор делать это неявно. Назовите меня сумасшедшим, но я не вижу в этом никакого преимущества.

Фактически, я могу сказать, что я честно никогда не видел никакого реального кода, который использует этот синтаксис. Единственное, что я могу найти в Google, - это глупость, подобная этомуCall - гораздо лучшая альтернатива там, в любом случае).

Using Заявления/Блокировки

В отличие от With, Using невероятно полезен и должен часто появляться в типичном коде VB.NET. Однако он очень ограничен в своей применимости: он работает только с объектами, тип которых реализует шаблон интерфейса IDisposable. Вы можете сказать это, проверив, имеет ли объект метод Dispose, который вы должны вызывать, когда вы закончите с ним, чтобы освободить неуправляемые ресурсы.

Это, кстати, правило, которое вы всегда должны соблюдать, когда объект имеет метод Dispose: вы всегда должны вызывать его всякий раз, когда вы закончите использовать этот объект. Если вы этого не сделаете, это не обязательно конец света - сборщик мусора может спасти ваш бекон, но это часть документально подтвержденного контракта и всегда хорошая практика с вашей стороны вызывать Dispose для каждого объекта, который его предоставляет.

Если вы попытаетесь завернуть создание объекта, который не реализует IDisposable в блоке Using, компилятор будет лаять на вас и генерировать ошибку. Это не имеет смысла для других типов, потому что его функция по существу эквивалентна блоку Try/Finally:

Try
    ' [1: Create/acquire the object]
    Dim g As Graphics = myForm.CreateGraphics()

    ' [2: Use the object]
    g.DrawLine(Pens.Blue, 10, 10, 100, 100)
    ' ... etc.
End Try
Finally
    ' [3: Ensure that the object gets disposed, no matter what!]
    g.Dispose()
End Finally

Но это уродливо и становится довольно громоздким, когда вы начинаете вложенность (например, если бы мы создали объект Pen, который также должен был быть удален). Вместо этого мы используем Using, который имеет тот же эффект:

' [1: Create/acquire the object]
Using g As Graphics = myForm.CreateGraphics()
    ' [2: Use the object]
    g.DrawLine(Pens.Blue, 10, 10, 100, 100)
    ' ...etc.
End Using  ' [3: Ensure that the object gets disposed, no matter what!]

Оператор Using работает как с объектами, которые вы сначала приобретаете (используя ключевое слово New, либо вызывая метод типа CreateGraphics), и с уже созданными вами объектами. В обоих случаях он гарантирует, что метод Dispose вызывается, даже если исключение выбрасывается где-то внутри блока, что гарантирует правильное расположение объектов неуправляемых ресурсов.

Меня немного пугает, что вы написали код в VB.NET, не зная о инструкции Using. Вы не используете его для создания всех объектов, но это очень важно, когда вы имеете дело с объектами, которые реализуют IDisposable. Вам обязательно нужно вернуться и повторно проверить свой код, чтобы убедиться, что вы используете его там, где это необходимо!

Ответ 3

Разница заключается в Using With...End End

Using cn as New OleDBConnection(MyConnectionString)
    With cn
        ' Do stuff with cn
    End With
End using

Вызывает cn.Dispose() автоматически при выходе из области видимости (End Using). Но в With New...End

With New OleDbConnection(MyConnectionString)
    ' Do stuff
End With

.Dispose() явно не вызывается.

Также с указанным объектом вы можете создавать часы и ?cn в непосредственном окне. С неназванным объектом вы не можете.

Ответ 4

Использование соединения... End Using: Будьте осторожны! Этот оператор закроет вашу базу данных соединение!

В середине модуля или формы (ов), то есть добавления или обновления записей, это закроет соединение. Когда вы пытаетесь выполнить другую операцию в этом модуле, вы получите ошибку базы данных. Для соединений я больше не использую его. Вы можете использовать команду Try... End Try withth the Using.

Я открываю соединение при входе в модуль и закрываю его при выходе. Это решает проблему.