Visual Studio has a refactoring snippet that creates a property from a field. This creates the property immediately after the field. This article describes a macro that puts the property further down in the file, with other properties.
The refactoring tools in Visual Studio are great. But I like to keep all my fields in one place and all my properties in another. So they look like:
#region Fields private int variable1; private string variable2; private double var3; #endregion #region Properties public int Variable1 { get { return variable1; } set { variable1 = value; } } public string Variable2 { get { return variable2; } set { variable2 = value; } } public double Var3 { get { return var3; } set { var3 = value; } } #endregion
Using the EncapsulateField snippet that comes with Visual Studio puts the newly created property directly after the field, so I then have to move it. This is ok once, but gets tedious after you have done it a few hundred times. So I have finally decided to do something about it.
I would have liked to have modified the snippet to move the property for me, but after hunting around for a way to do this, came to the conclusion that it wasn't possible. So I decided to write a macro to do it instead. It uses the built in EncapsulateField snippet to create the property, but then moves it to where other properties are defined.
Imports System Imports EnvDTE Imports EnvDTE80 Imports System.Diagnostics Imports System.Text.RegularExpressions Public Module Refactoring Dim nCurLine As Int16 'Dim nCurCol As Int16 Sub ExtractProperty() SaveCursorPosition() EncapsulateField() 'Create the property from the field we are on DTE.ActiveDocument.Selection.CharLeft() 'Wait for dialogs to be closed DTE.ActiveDocument.Selection.CharRight() Dim fieldStr As String Dim propertyStr As String 'Get field If RegExSelect("<.+[^;]", False) Then fieldStr = DTE.ActiveDocument.Selection.Text 'Get generated property If RegExSelect("\n(.|[\n])#\}\n:Wh+\}") Then propertyStr = DTE.ActiveDocument.Selection.Text Dim fldCount As Int16 fldCount = Regex.Matches(propertyStr, fieldStr).Count 'Make sure property matches field (it won't if the user cancelled the refactoring) If fldCount = 2 Then DTE.ActiveDocument.Selection.Cut() 'Cut the property out DTE.ActiveDocument.Selection.CharLeft() RegExSelect(";", False) 'Get the previous field If RegExSelect("<.+[^;]", False) Then fieldStr = DTE.ActiveDocument.Selection.Text If RegExSelect("get:Wh*\{:Wh*return:Wh+" & fieldStr & ";(.|[\n])#\}\n:Wh*\}") Then DTE.ActiveDocument.Selection.EndOfLine() DTE.ActiveDocument.Selection.Paste() End If End If End If End If End If RestoreCursorPosition() End Sub Private Sub EncapsulateField() DTE.ExecuteCommand("Refactor.EncapsulateField") End Sub Function RegExSelect(ByVal searchExpr As String) As Boolean Return RegExSelect(searchExpr, True) End Function Function RegExSelect(ByVal searchExpr As String, ByVal direction As Boolean) As Boolean DTE.Find.FindWhat = searchExpr DTE.Find.Target = vsFindTarget.vsFindTargetCurrentDocument DTE.Find.MatchCase = False DTE.Find.MatchWholeWord = False DTE.Find.Backwards = Not direction DTE.Find.MatchInHiddenText = True DTE.Find.PatternSyntax = vsFindPatternSyntax.vsFindPatternSyntaxRegExpr DTE.Find.Action = vsFindAction.vsFindActionFind Return (DTE.Find.Execute() <> vsFindResult.vsFindResultNotFound) End Function Private Sub SaveCursorPosition() nCurLine = DTE.ActiveDocument.Selection.CurrentLine End Sub Private Sub RestoreCursorPosition() DTE.ActiveDocument.Selection.GoToLine(nCurLine) DTE.ActiveDocument.Selection.EndOfLine() End Sub End Module
To use the macro above, open the macro explorer, create a new module (e.g. "Refactoring"), copy and paste the text above in (replacing the text in the created module) and save it. You should then have a macro called "ExtractProperty". To make it easier to use, you may want to assign a keyboard shortcut to it from the tools, customize menu option.
The first property that you create will have to be moved manually. This should be done with the built in EncapsulateField snippet. Subsequent fields will be moved to the correct place. For example:
#region Fields private int variable1; private string variable2; private double var3; #endregion #region Properties public int Variable1 { get { return variable1; } set { variable1 = value; } } #endregion
Putting the cursor anywhere on the line with variable2 and running the macro will produce the following code:
#region Fields private int variable1; private string variable2; private double var3; #endregion #region Properties public int Variable1 { get { return variable1; } set { variable1 = value; } } public string Variable2 { get { return variable2; } set { variable2 = value; } } #endregion
Note that the macro shouldn't do anything if you cancel the property creation from the EncapsulateField snippet dialog.