ONDotNet.com    
 Published on ONDotNet.com (http://www.ondotnet.com/)
 See this if you're having trouble printing code examples


Refactoring Support for Visual Basic 2005

by Wei-Meng Lee
05/31/2005

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!

Extract Method

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).

figure 1
Figure 1. Extracting a block of code as a method

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.

figure 2
Figure 2. Adding a new method

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).

figure 3
Figure 3. The newly added method

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).

figure 4
Figure 4. Changing the method name

Reorder Parameters

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).

figure 5
Figure 5. Extracting the block of code as a method

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

figure 6
Figure 6. Changing the name of the method

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).

figure 7
Figure 7. Reordering the parameters

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.

figure 8
Figure 8. Confirming the changes
Visual Basic 2005: A Developer's Notebook

Related Reading

Visual Basic 2005: A Developer's Notebook
By Matthew MacDonald

Introduce Constant

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).

figure 9
Figure 9. Introducing a constant

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.

figure 10
Figure 10. You can change the name of the constant

Move Declaration Near Reference

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).

figure 11
Figure 11. Moving the declaration near the reference

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

Split Initialization From Declaration

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).

figure 12
Figure 12. Splitting initialization from declaration

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

Move Initialization to Declaration

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).

figure 13
Figure 13. Moving the initialization to the declaration

Introduce Local

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).

figure 14
Figure 14. Introducing a local variable

Your code will now look like this:


Dim lSizeWidth As Integer = Me.Size.Width
If lSizeWidth > 200 Then
  ...
End If

Inline Temp

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.

figure 15
Figure 15. Replacing a variable with its original expression

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

Extract Property

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.

figure 16
Figure 16. Extracting a block of code as a 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)

Create Overload

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).

figure 17
Figure 17. Creating an overloaded method

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

figure 18
Figure 18. Modifying the overloaded method

Encapsulate Field

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).

figure 19
Figure 19. Encapsulating a variable as a field

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

Reverse Conditional

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).

figure 20
Figure 20. Reversing the logic of your code

The result would be:


If num >= 0 Then
  MsgBox("0 or positive")
Else
  MsgBox("Negative")
End If

Simplify Expression

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).

figure 21
Figure 21. Simplifying an expression

The code would be simplified as:


Dim obj As Object
If obj IsNot Nothing Then
   ...
End If

Replace Temp with Query

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).

figure 22
Figure 22. Replacing a variable with a method call

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))

Split Temporary Variable

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).

figure 23
Figure 23. Splitting a temporary variable

The resultant code will be:


Dim i As Integer
For i = 0 To 10
  ...
Next

Dim lSplitI As Integer
lSplitI = InputBox("Enter a number")

Summary

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.