Lately I have been doing some refactoring of code as I go through it.
Trying to name variables correctly, breaking up long methods, trying to adhere to some coding standards.
One way that I have been employing to clean up code is to convert very long method signatures, or calls to methods with many parameters from LONG single line entities to shorter multi-line blocks.
This is simple, but tedious. So I wrote a VS.Net macro to do it for me.
Simply copy and paste the macro code (paste into wordpad first to get rid of the missing newline problem) at the bottom of this article into a macro. Then all you have to do is highlight the entire row you want to “narrow”, and run the macro. You can always Cntl+z out of it if you want to undo the changes.
The results are good! The following are examples of a long method signature, and a call to a method with a lot of arguments, and then the refactored results.
'*** Long method signature
Public Function ActivitySave(ByVal Activity As MyNamespace.Business.Equipment.Activity, ByVal StartTime As DateTime, ByVal EndTime As DateTime, ByVal StatusOverride As System.Nullable(Of MyNamespace.Business.Data.Criteria.Equipment.ActivityStatusEnum), ByVal Clerk As Integer) As Integer
'*** long method call
ActivityID = MainActivity.ActivitySave(Activity.ActivityID, Activity.Status, Activity.PurposeNotes, Activity.JobIndex, Activity.CategoryID, Activity.RequestedStartDate, Activity.RequestedEndDate, Activity.EquipmentID, Activity.PlanStartDate, Activity.PlanEndDate, Activity.ActualStartDate, Activity.ActualEndDate, Activity.DiscountScheduleID, Activity.DiscountOffset, Activity.CodeID, Activity.RentalRate, Activity.RowVersion, Clerk)
Here is the result of the refactoring:
'*** Refactored long method signature
Public Function ActivitySave(ByVal Activity As MyNamespace.Business.Equipment.Activity, _
ByVal StartTime As DateTime, _
ByVal EndTime As DateTime, _
ByVal StatusOverride As System.Nullable(Of MyNamespace.Business.Data.Criteria.Equipment.ActivityStatusEnum), _
ByVal Clerk As Integer) As Integer
'*** Refactored long call
ActivityID = MainActivity.ActivitySave(Activity.ActivityID, _
Activity.Status, _
Activity.PurposeNotes, _
Activity.JobIndex, _
Activity.CategoryID, _
Activity.RequestedStartDate, _
Activity.RequestedEndDate, _
Activity.EquipmentID, _
Activity.PlanStartDate, _
Activity.PlanEndDate, _
Activity.ActualStartDate, _
Activity.ActualEndDate, _
Activity.DiscountScheduleID, _
Activity.DiscountOffset, _
Activity.CodeID, _
Activity.RentalRate, _
Activity.RowVersion, _
Clerk)
Here is the macro.
Public Sub NarrowMethodsAndCalls()
'Create an Undo context object so all the changes can be
'undone by CTRL+Z
Dim oUnDo As UndoContext = DTE.UndoContext
'Supress the User Interface. This will make it run faster
'and make all the changes appear once
DTE.SuppressUI = True
Try
Dim oTextSelection As TextSelection = DTE.ActiveWindow.Selection
Dim sOrigText As String = oTextSelection.Text
Dim RegExp As New System.Text.RegularExpressions.Regex("([ .=_a-zA-Z0-9]*)(")
Dim Match As System.Text.RegularExpressions.Match = RegExp.Match(sOrigText)
If Match.Success Then
Dim sMethod As String = Match.ToString
Dim sParametersAndReturn() As String = sOrigText.Replace(sMethod, "").Split(",")
Dim sFirstLineWhiteSpace As String
Dim sb As New System.Text.StringBuilder
sb.Append(" ", Trim(sMethod).Length)
sFirstLineWhiteSpace = sb.ToString
'*** redo the first line
oTextSelection.Text = sMethod & sParametersAndReturn(0) & ", _"
oTextSelection.NewLine()
oTextSelection.Text = sFirstLineWhiteSpace
For i As Integer = 1 To sParametersAndReturn.Length - 2
oTextSelection.Text = Trim(sParametersAndReturn(i)) & ", _"
oTextSelection.NewLine()
Next
oTextSelection.Text = Trim(sParametersAndReturn(sParametersAndReturn.Length - 1))
oTextSelection.NewLine()
Else
MsgBox("failed to find function regexp match")
End If
Catch ex As Exception
MsgBox("Error: " & ex.ToString)
Finally
'If an error occured, then need to make sure that the undo context is cleaned up.
'Otherwise, the editor can be left in a perpetual undo context
If oUnDo.IsOpen Then
oUnDo.Close()
End If
DTE.SuppressUI = False
End Try
End Sub