Microsoft recently announced that they have teamed up with Developer Express Inc. to release Refactor! for Visual Basic 2005 Beta 2, a free plugin for Visual Studio that enables Visual Basic developers to simplify and restructure source code inside of Visual Studio 2005. This announcement came shortly after Microsoft indicated that, due to timing constraints, Visual Studio 2005 will not come with refactoring support for VB2005 (though it is supported in C#; see my earlier article here). This move has sparked a lot of developer displeasure, again raising the question of whether Microsoft ever took VB seriously. Now, with the release of Refactor! for VB2005, a lot of VB developers are smiling again.
In this article, I will take you on a tour of Refactor's refactoring feature and how you can use it to improve your code. One significant advantage of using Refactor is that all of the refactoring is done inline, with no pop-up dialog boxes to block your view of the code in question. So let the tour begin!
Suppose you have the following block of code:
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Dim num, sum As Integer
num = 10
For i As Integer = 0 To num
sum += i
Next
End Sub
You can extract the For loop as a method. To do so, highlight the block that
you want to extract as a method, right-click, and select Refactor -> Extract
Method (see Figure 1).

You will be asked for the position to which to insert the new method (see Figure 2). You
can use the cursor key on your keyboard to move up or down. Press Enter to
insert the new method as indicated by the arrow. Pressing Esc will cancel this
add new method operation.

Refactor automatically uses an appropriate name for this newly inserted method. The code that originally contains this block of code would be replaced with a method call. The big red arrow indicates the newly added method (see Figure 3).

If you don't like the name suggested, you can always click on the method name (highlighted in green) and the corresponding method call will be changed as well (see Figure 4).

Suppose you have the following block of code:
Private Sub Form1_Load(ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Dim radius As Single = 3.5
Dim height As Single = 5
'---Volume of Cylinder
Dim volume As Single = 3.14 * radius ^ 2 * height
End Sub
You can extract the statement that calculates the volume of a cylinder as a method, using the steps as described in the last section (see Figure 5).

You can change the name of the method to VolumeOfCylinder to better reflect the
purpose of the function (see Figure 6).

Notice that the new method now has two input parameters (radius and height).
You can change the order of the parameters; for example, you might want to pass
in the height of the cylinder first, then followed by radius. In this case,
right-click on either of the parameters and select Refactor -> Reorder
Parameter. You can use the cursor keys to reorder the parameters and press Enter
when you are done (see Figure 7).

When you press Enter, Refactor will update the calling statement and ask that
you confirm the changes (see Figure 8). Click on the "tick" icon to confirm the
change.

|
Related Reading Visual Basic 2005: A Developer's Notebook |
|
In the VolumeofCylinder() function, you used the constant 3.14 for the value of
Pi. Ideally, you should define a constant for this. Highlight 3.14,
right-click, and select Refactor -> Introduce Constant (see Figure 9).

Refactor will use a default name (in this DBL_, based on the data type of the
constant) for the newly added constant (see Figure 10). You can change the
constant to a more meaningful name. In this case, change it to PI.

Sometimes you won't use a variable that you have declared until several lines after the declaration. To improve readability of your code, it is always better to declare the variables near where they are used.
For example, in the following code segment, the variable radius is not
immediately used after its declaration. You might want to move the declaration
closer to where it is being used.
Private Sub Form1_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Dim radius As Single = 3.5
Dim height As Single = 5
'---Volume of Cylinder
Dim volume As Single = VolumeOfCylinder(height, radius)
End Sub
You can right-click on the declaration statement and then select Refactor -> Move Declaration Near Reference (see Figure 11).

The radius variable declaration is now moved to the line before where it is first
used:
Private Sub Form1_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Dim height As Single = 5
'---Volume of Cylinder
Dim radius As Single = 3.5
Dim volume As Single = VolumeOfCylinder(height, radius)
End Sub
There may be times where you want to split an initialization statement from declaration (VB2005 allows you to declare and initialize a variable at the same time). To do so, simply right-click on the relevant variable and select Refactor -> Split Initialization From Declaration (see Figure 12).

The code will now become:
Private Sub Form1_Load( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs)
Dim height As Single = 5
'---Volume of Cylinder
Dim radius As Single
radius = 3.5
Dim volume As Single = VolumeOfCylinder(height, radius)
End Sub
This option is the inverse of the previous option. Instead of splitting the initialization from the declaration, it now moves the initialization into the declaration. Simply right-click on the relevant variable and select Refactor -> Move Initialization To Declaration (see Figure 13).

Sometimes you have code that looks like this:
If Me.Size.Width > 200 Then
...
End If
The Me.Size.Width expression is both lengthy and makes debugging difficult if
it is used in more than one place. In this case, it is better to use a local
variable to replace it. To do so, right-click on the variable and select
Refactor -> Introduce Local (see Figure 14).

Your code will now look like this:
Dim lSizeWidth As Integer = Me.Size.Width
If lSizeWidth > 200 Then
...
End If
|
This option is the inverse of the previous option. Instead of using a variable to replace a lengthy expression, it now replaces all of the variables with the original expression. Consider the following code segment:
Dim lSizeWidth As Integer = Me.Size.Width
If lSizeWidth > 200 Then
...
End If
If lSizeWidth > 100 Then
...
End If
If you right-click on lSizeWidth and select Refactor -> Inline Temp (see
Figure 15), it will now replace all occurrences of the lSizeWidth variable with Me.Size.Width.

Your code will now become:
If Me.Size.Width > 200 Then
...
End If
If Me.Size.Width > 100 Then
...
End If
There's one caveat, though. If you have a statement that performs some changes
to the lSizeWidth variable (see the code below), then Refactor will not be
able to perform the Inline Temp refactoring for you:
Dim lSizeWidth As Integer = Me.Size.Width
If lSizeWidth > 200 Then
...
End If
lSizeWidth -= 100
If lSizeWidth > 100 Then
...
End If
Consider the following block of code, which consumes a web service:
Dim result() As StockWS.Quote = _
My.WebServices.StockQuotes.GetStockQuotes("MSFT")
MsgBox(result(0).StockQuote)
You may reference the web service in a number of places in your application. In such cases, it may be better to extract the above logic and expose it as a property so that other parts of your code can simply access the property and you will not need to write code to consume the web service again. To do so, highlight the web service code (see Figure 16), right-click, and select Refactor -> Extract Property.

The web service code would now be exposed as a property and the original code would be replaced with a property call:
Private ReadOnly Property MyProperty() As StockWS.Quote()
Get
Return My.WebServices.StockQuotes.GetStockQuotes("MSFT")
End Get
End Property
...
...
Dim result() As StockWS.Quote = MyProperty
MsgBox(result(0).StockQuote)
You can create overloaded methods easily in your class by right-clicking on a method name and then selecting Refactor -> Create Overload (see Figure 17).

An overloaded method is created and you can use the various keyboard options (see Figure 18) to include/exclude parameters.

|
Consider the following class definition with two public members:
Public Class Point
Public x As Integer
Public y As Integer
End Class
Instead of exposing two public members, it would be better to expose them as
properties. To do so, right-click on x and select Refactor -> Encapsulate
Field (see Figure 19).

The resultant class would look like this:
Public Class Point
Public Property X() As Integer
Get
Return _x
End Get
Set(ByVal value As Integer)
_x = value
End Set
End Property
Private _x As Integer
Public y As Integer
End Class
There is one interesting aspect of how Refactor works. Instead of declaring the two pubic members separately, say you declare them in one single statement:
Public Class Point
Public x, y As Integer
End Class
If you now use Refactor to encapsulate x as a field, you get the following
(notice that now _x is of Object type):
Public Class Point
Public Property X() As Integer
Get
Return _x
End Get
Set(ByVal value As Integer)
_x = Value
End Set
End Property
Private _x As Object
Public y As Integer
End Class
Often time we write code that test for the equality (or inequality) of expressions. Consider the following:
If num < 0 Then
MsgBox("Negative")
Else
MsgBox("0 or positive")
End If
You can reverse the condition by highlighting the first condition and then selecting Refactor -> Reverse Conditional (see Figure 20).

The result would be:
If num >= 0 Then
MsgBox("0 or positive")
Else
MsgBox("Negative")
End If
The following block of code should be familiar to most people:
Dim obj As Object
If Not (obj Is Nothing) Then
...
End If
To simplify the expression and aid readability, you can right-click on the expression and then select Refactor -> Simplify Expression (see Figure 21).

The code would be simplified as:
Dim obj As Object
If obj IsNot Nothing Then
...
End If
Consider the following block of code:
'---Volume of Cylinder
Dim radius As Single = 3.5
Dim volume As Single = VolumeOfCylinder(height, radius)
MsgBox(volume)
You can replace the volume variable with a method. To do so, right-click on the
volume variable and select Refactor -> Replace Temp with Query (see Figure
22).

The code block now becomes (with a newly created GetVolume() method):
Private Function GetVolume( _
ByVal height As Single, _
ByVal radius As Single) As Single
Return VolumeOfCylinder(Height, radius)
End Function
'---Volume of Cylinder
Dim radius As Single = 3.5
MsgBox(GetVolume(height, radius))
Often times you declare a single variable and use it for a variety of purposes.
This is error-prone and makes debugging difficult. Consider the following (i is
used as loop variant as well as a placeholder for the InputBox() method):
Dim i As Integer
For i = 0 To 10
...
Next
i = InputBox("Enter a number")
Right-click on i and select Refactor -> Split Temporary Variable (see Figure
23).

The resultant code will be:
Dim i As Integer
For i = 0 To 10
...
Next
Dim lSplitI As Integer
lSplitI = InputBox("Enter a number")
With the new Refactor for Visual Basic 2005, there is now no reason why you can say Visual Basic is not for professional developers. What is best is that all Visual Studio 2005 users can download this fantastic tool for free. What are you waiting for? Start coding and improve your code today!
Wei-Meng Lee (Microsoft MVP) http://weimenglee.blogspot.com is a technologist and founder of Developer Learning Solutions http://www.developerlearningsolutions.com, a technology company specializing in hands-on training on the latest Microsoft technologies.
Return to ONDotNet
Copyright © 2009 O'Reilly Media, Inc.