С End With против использования в VB.NET

Я только что узнал, что, как и C #, 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

ОБНОВЛЕНИЕ:

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

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

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

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


person yu_ominae    schedule 21.03.2013    source источник
comment
Итак, как я понимаю, если из ответов ниже, единственный раз, когда Using лучше, чем With New ..., - это когда работаешь с неуправляемым объектом. Если кто-то не может предоставить мне хороший пример того, почему бы не использовать With New ... для локального одноразового объекта, я не понимаю, почему я не должен использовать его, чтобы мой код оставался незагроможденным.   -  person yu_ominae    schedule 21.03.2013


Ответы (4)


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

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

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

person Jacob Seleznev    schedule 21.03.2013
comment
Вы имеете в виду, что Using вызовет Dispose() метод неуправляемых ресурсов? Я думал, что все объекты, входящие в структуру .Net, управляются? - person yu_ominae; 21.03.2013
comment
К неуправляемым ресурсам относятся: дескриптор файла, оболочка COM, соединение с базой данных. Объявите метод Dispose, который реализует всю логику очистки ресурсов, и компилятор вызовет его в блоке Using. - person Jacob Seleznev; 21.03.2013
comment
Спасибо. Итак, если я получу это правильно, соединение с БД, для которого не было Dispose() явно вызвано, никогда не будет собираться сборщиком мусора? - person yu_ominae; 21.03.2013
comment
@yu_ominae: управляемый ресурс - это объект, который попросил какую-то внешнюю сущность сделать что-то от его имени до дальнейшего уведомления, запросил у сборщика мусора уведомление, если он заброшен, и если такое уведомление будет предоставлено, в свою очередь, сообщит другой сущности о своих услугах больше не требуются. Неуправляемый ресурс - это соглашение с внешней организацией о каких-либо действиях от имени объекта до дальнейшего уведомления, в сочетании с обещанием объекта доставить такое уведомление, но без каких-либо средств обеспечения доставки уведомления, если объект будет оставлен. - person supercat; 28.08.2013
comment
@supercat Спасибо, красивое объяснение! - person yu_ominae; 29.08.2013
comment
@yu_ominae: Спасибо. Я считаю, что неуправляемый ресурс часто определяется в терминах файлов, дескрипторов GDI и других подобных вещей. Хотя дескриптор GDI является неуправляемым ресурсом, это потому, что код, который получил его от GDI , также пообещал GDI, что он будет выпущен. Обратите внимание, что неуправляемые ресурсы могут существовать полностью в управляемом коде. Подписки на события и блокировки являются наиболее распространенными примерами; перерабатываемые объединенные объекты - другое. Предположим, например, что этот код должен будет создать и отказаться от множества массивов из 1024 элементов double. - person supercat; 29.08.2013
comment
@yu_ominae: Повторное создание и отказ от double[1024 массивов может быть дорогостоящим. Если коду на самом деле не нужен double[], но можно обойтись оболочкой, реализующей double this[int], фабрика оболочки может иметь double[][], а структура оболочки может включать два значения UInt16, которые указывают слот массива фабрики, которым она владеет, вместе с счетчик последовательности распределения. При условии, что код, который выполняется с каждым массивом, правильно вызывает Dispose, такой подход может иногда значительно улучшить производительность сборки мусора. - person supercat; 29.08.2013

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

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

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

Но вы используете With не поэтому. Причина в том, что он позволяет вам последовательно устанавливать несколько свойств для глубоко вложенного объекта. Другими словами, предположим, что у вас есть объект, для которого вы хотите установить набор свойств, и вы получаете к нему доступ следующим образом: MyClass.MemberClass.AnotherMemberClass.Items(0). Видите все эти точки? (Теоретически) может стать неэффективным писать код, который должен снова и снова проходить через эту серию точек для доступа к одному и тому же объекту каждый раз, когда вы устанавливаете для него свойство. Если вы знаете что-нибудь о C или 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. Однако его применимость очень ограничена: он работает только с объектами, тип которых реализует _ 27_ шаблон интерфейса. Вы можете убедиться в этом, проверив, есть ли у объекта метод Dispose, который вы должны вызывать каждый раз, когда вы закончите с ним, чтобы освободить какие-либо неуправляемые ресурсы.

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

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

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. Вам обязательно стоит вернуться и перепроверить свой код, чтобы убедиться, что вы используете его там, где это необходимо!

person Cody Gray    schedule 21.03.2013
comment
Хороший ответ, спасибо. Я не согласен с вашим мнением о ключевом слове With New, оно позволяет избежать объявления переменной, что, на мой взгляд, вполне нормально, когда использование объекта ограничено методом и используется только один раз. Мне, наверное, стоит переписать все с Using сейчас, но поскольку я всегда использую With, а затем Try Catch Finally, чтобы избавиться от своего объекта, я думаю, что сейчас у меня все в порядке :) - person yu_ominae; 21.03.2013
comment
Вот пример того, как я бы использовал With New stackoverflow.com/questions/15423898/ Конечно, с Using было бы намного лучше смотреться, но видите ли вы в этом что-то критически неправильное? - person yu_ominae; 21.03.2013
comment
Я согласен с @yu_ominae; Замечательно иметь возможность просто пойти With New MySubForm ... do stuff ... End With, так как вы мало что сделаете с подформой после того, как получите результат диалога. Одна вещь, которую я хотел бы увидеть в блоке With, - это возможность иметь краткую ссылку на обернутый объект, скажем, через двойную точку (..) или шляпу (^). - person SteveCinq; 18.05.2017

Разница в 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 в непосредственном окне. С безымянным объектом вы не можете.

person djv    schedule 21.03.2013

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

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

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

person David Petty    schedule 08.06.2017
comment
Это не отвечает на вопрос. - person James Hyde; 04.08.2017