10

I just found out that like C#, VB.NET also has the using keyword.

Until now I thought it didn't have it (stupid of me, I know...) and did stuff like this instead:

With New OleDbConnection(MyConnectionString)
   ' Do stuff
End With

What are the implications of this compared to doing it with a using statement like this

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

UPDATE:

I should add that I am familiar with what the using statement does in that it disposes of the object when the construct is exited.

However, as far as I understand the With New ... construct will have the object mark the object as ready for garbage collection when it goes out of scope.

So my question really is, is the only difference the fact that with using I will release the memory right away, whereas with the With construct it will be released whenever the GC feels like it? Or am I missing something bigger here?

Are there any best practice implications? Should I go and rewrite all the code with I used With New MyDisposableObject() ... End With as Using o as New MyDisposableObject()?

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
yu_ominae
  • 2,975
  • 6
  • 39
  • 76
  • So as I undertand if from the answers below, the only time `Using` is better than `With New ...` is when dealing with an unmanaged object. Unless somebody can provide me a good example of why not to use `With New ...` for a local single-use object, I don't see why I should not use it to keep my code uncluttered. – yu_ominae Mar 21 '13 at 04:43

4 Answers4

17

With Statements/Blocks

However, as far as I understand the With New ... construct will have the object mark the object as ready for garbage collection when it goes out of scope.

This is both true and not true. It is true in the sense that all objects are "marked" (purists might quibble with this terminology, but the details are not relevant) as ready for garbage collection when they go out of scope. But then in that sense, it is also not entirely true, as there's nothing special about the With keyword with respect to this behavior. When an object goes out of scope, it is eligible for garbage collection. Period. That's true for method-level scope and it's true for block-level scope (e.g., With, For, Using, etc.).

But that's not why you use With. The reason is that it allows you to set multiple properties in sequence on a deeply-nested object. In other words, assume you have an object on which you want to set a bunch of properties, and you access it this way: MyClass.MemberClass.AnotherMemberClass.Items(0). See all those dots? It can (theoretically) become inefficient to write code that has to work through that series of dots over and over to access the exact same object each time you set a property on it. If you know anything about C or C++ (or any other language that has pointers), you can think of each of those dots as implying a pointer dereference. The With statement basically goes through all of that indirection only once, storing the resulting object in a temporary variable, and allowing you to set properties directly on that object stored in the temporary variable.

Perhaps some code would help make things clearer. Whenever you see a dot, think might be slow!

Assume that you start out with the following code, retrieving object 1 from a deeply-nested Items collection and setting multiple properties on it. See how many times we have to retrieve the object, even though it's exactly the same object every time?

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

Now we modify that code to use a With block:

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

The effect here, however, is identical to the following code:

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

Granted, you don't introduce a new scope, so tempObj won't go out of scope (and therefore be eligible for garbage collection) until the higher level scope ends, but that's hardly ever a relevant concern. The performance gain (if any) attaches to both of the latter two code snippets.

The real win of using With blocks nowadays is not performance, but readability. For more thoughts on With, possible performance improvements, stylistic suggestions, and so on, see the answers to this question.

With New?

Adding the New keyword to a With statement has exactly the same effect that we just discussed (creating a local temporary variable to hold the object), except that it's almost an entirely pointless one. If you need to create an object with New, you might as well declare a variable to hold it. You're probably going to need to do something with that object later, like pass it to another method, and you can't do that in a With block.

It seems that the only purpose of With New is that it allows you to avoid an explicit variable declaration, instead causing the compiler to do it implicitly. Call me crazy, but I see no advantage in this.

In fact, I can say that I have honestly never seen any actual code that uses this syntax. The only thing I can find on Google is nonsense like this (and Call is a much better alternative there anyway).

Using Statements/Blocks

Unlike With, Using is incredibly useful and should appear frequently in typical VB.NET code. However, it is very limited in its applicability: it works only with objects whose type implements the IDisposable interface pattern. You can tell this by checking to see whether the object has a Dispose method that you're supposed to call whenever you're finished with it in order to release any unmanaged resources.

That is, by the way, a rule you should always follow when an object has a Dispose method: you should always call it whenever you're finished using the object. If you don't, it's not necessarily the end of the world—the garbage collector might save your bacon—but it's part of the documented contract and always good practice on your part to call Dispose for each object that provides it.

If you try to wrap the creation of an object that doesn't implement IDisposable in a Using block, the compiler will bark at you and generate an error. It doesn't make sense for any other types because its function is essentially equivalent to a Try/Finally block:

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

But that's ugly and becomes rather unwieldy when you start nesting (like if we'd created a Pen object that needed to be disposed as well). Instead, we use Using, which has the same effect:

' [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!]

The Using statement works both with objects you are first acquiring (using the New keyword or by calling a method like CreateGraphics), and with objects that you have already created. In both cases, it ensures that the Dispose method gets called, even if an exception gets thrown somewhere inside of the block, which ensures that the object's unmanaged resources get correctly disposed.

It scares me a little bit that you have written code in VB.NET without knowing about the Using statement. You don't use it for the creation of all objects, but it is very important when you're dealing with objects that implement IDisposable. You definitely should go back and re-check your code to ensure that you're using it where appropriate!

Community
  • 1
  • 1
Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • 1
    Nice answer thanks. I do disagree on your view of the `With New` keyword, it saves declaring a variable which I think is just fine when the object's use is confined to the method and is used only once. I should probably rewrite everything with `Using` now, but since I always use `With` and then `Try Catch Finally` to dispose of my object I think I'm good for now :) – yu_ominae Mar 21 '13 at 04:13
  • Here's an example of how I would use `With New` http://stackoverflow.com/questions/15423898/having-trouble-updating-edit-database/15425375#15425375 Of course it would look much nicer with `Using`, but do you see anything critically wrong with that? – yu_ominae Mar 21 '13 at 04:20
  • 1
    I agree with @yu_ominae; it's great to be able to just go `With New MySubForm ... do stuff ... End With` as you won't do much with a sub-form once you have the dialog result. One thing I would _love_ to see in a `With` block tho is the ability to have a short-hand reference to the wrapped object via, say, a double dot (..) or hat (^). – SteveCinq May 18 '17 at 20:59
9

By using With...End With, you can perform a series of statements on a specified object without specifying the name of the object multiple times.

A Using block behaves like a Try...Finally construction in which the Try block uses the resources and the Finally block disposes of them.

Managed resources are disposed by the garbage collector without any extra coding on your part. You do not need Using or With statements. Sometimes your code requires unmanaged resources. You are responsible for their disposal. A Using block guarantees that the Dispose method on the object is called when your code is finished with them.

Jacob Seleznev
  • 8,013
  • 3
  • 24
  • 34
  • By this, do you mean that `Using` will call the `Dispose()` method of unmanaged resources? I thought all objects that are part of the .Net framework were managed? – yu_ominae Mar 21 '13 at 04:16
  • Unmanaged resources are: a file handle, a COM wrapper, a database connection. Declare the Dispose method that implements all resource cleanup logic and compiler will call it in the **Using** block. – Jacob Seleznev Mar 21 '13 at 04:24
  • Thanks. So if I get this correctly, a DB connection which has not had `Dispose()` called on it explicitly will never be garbage collected? – yu_ominae Mar 21 '13 at 04:29
  • 2
    @yu_ominae: A managed resource is an object that has asked some outside entity to do something on its behalf until further notice, has asked the garbage collector for notification if it's abandoned, and if given such notification will in turn tell the other entity its services are no longer required. An unmanaged resource is an agreement with an outside entity to do something on an object's behalf until further notice, combined with a promise by the object to deliver such notice, but without any means of ensuring the notice will get delivered if the object is abandoned. – supercat Aug 28 '13 at 16:45
  • @supercat Thanks, that's a pretty neat explanation! – yu_ominae Aug 28 '13 at 23:41
  • @yu_ominae: Thanks. I think it unfortunate that "unmanaged resource" is often "defined" in terms of files, GDI handles, and other such things. While a GDI handle is an unmanaged resource, that's because code that has acquired one from the GDI *has also promised the GDI that it will be released*. Note that it's possible for unmanaged resources to exist *entirely within managed code*. Event subscriptions and locks are the most common examples; recyclable pooled objects are another. Suppose, for example, that code will need to create and abandon a lot of 1024-element arrays of `double`. – supercat Aug 29 '13 at 15:00
  • @yu_ominae: Repeated creation and abandonment of `double[1024` arrays can be expensive. If the code doesn't actually need a `double[]` but could get by with a wrapper that implements `double this[int]`, the wrapper factory could have a `double[][]`, and a wrapper struct could include two `UInt16` values that indicate slot of the factory's array it owns, along with an allocation sequence count. Provided that code which is done with each "array" calls `Dispose` properly, such an approach may sometimes greatly improve GC performance. – supercat Aug 29 '13 at 15:15
4

The difference is the Using With...End End

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

Calls cn.Dispose() automatically when going out of scope (End Using). But in the With New...End

With New OleDbConnection(MyConnectionString)
    ' Do stuff
End With

.Dispose() is not explicitly called.

Also with the named object, you can create watches and ?cn in the immediate window. With the unnamed object, you cannot.

djv
  • 15,168
  • 7
  • 48
  • 72
0

Using connection... End Using : Be careful !!! This statement will close your database connection !

In the middle of a module or form(s), i.e.adding or updating records, this will close the connection. When you try to do another operation in that module you will receive a database error. For connections, I no longer use it. You can use the Try... End Try wihthouth the Using statement.

I open the connection upon entry to the module and close it it upon exit. That solves the problem.