I find it quite ironical that many developers spend hours to debate which language is the most efficient or productive, and yet forget to learn how to use the tool with which they spend most of their time: the Visual Studio IDE.
The best way to increase productivity with Visual Studio is to write macros that automate repetitive tasks. There are many commercial and freeware add-ins on the market, but I rarely find one that does exactly what I need. In cases like this I just write a macro, either from scratch or starting with a recorded macro that captures the actions that I want to repeat.
For example, I found that I typically prototype my classes with Public fields, but then I convert them to properties when I convert the prototype to the "real" code. The conversion process takes me a lot of time. To see what I mean, I typically start with a simple variable such as
' The name of the element
Public Name As String = "Francesco"
and I convert it into something like this:
' The name of the element
Private m_Name As String = "Francesco"
Public Property Name() As String
Get
Return m_Name
End Get
Set(ByVal Value As String)
m_Name = Value
End Set
End Property
At last, some months ago I decided to write a macro that automates this conversion. It took me about 30 minutes, but in these months it saved me hours. Here it is:
Imports
EnvDTE
Imports System.Text.RegularExpressions
Public
Module CodeArchitectsMacros
Dim repPattern As String
Dim repPatternReadOnly As String
Sub ConvertVariables()
' Determine current language by looking at the extension of the current document.
Dim doc As Document = DTE.ActiveDocument
If doc Is Nothing Then Exit Sub
Dim docName As String = doc.Name.ToLower()
' Read all the text lines touched by the selection.
Dim sel As TextSelection = CType(DTE.ActiveDocument.Selection, TextSelection)
Dim ed1 As EditPoint = sel.AnchorPoint.CreateEditPoint()
ed1.EndOfLine() : ed1.StartOfLine() : ed1.StartOfLine()
Dim ed2 As EditPoint = sel.BottomPoint.CreateEditPoint()
ed2.EndOfLine()
Dim text As String = ed1.GetText(ed2)
' The find and replacement pattern depend on the current language.
Dim findPattern As String
If docName.EndsWith(".vb") Then
findPattern = "(?<indent>[\t ]+)Public\s+(?<static>Shared\s+)?(?<readonly>ReadOnly\s+)?" _
& "(?<name>\w+)\s+As\s+(?<type>\S+)(?<init>.*?)\n"
' {0}=property name, {1}=property type, {2}=static keyword, {3} initvalue,
' {4}=CR-LF, {5}=Tab, {6}=indent
repPattern = "{6}Private {2}m_{0} As {1}{3}{4}" _
& "{6}Public {2}Property {0}() As {1}{4}" _
& "{6}{5}Get{4}" _
& "{6}{5}{5}Return m_{0}{4}" _
& "{6}{5}End Get{4}" _
& "{6}{5}Set(ByVal Value As {1}){4}" _
& "{6}{5}{5}m_{0} = Value{4}" _
& "{6}{5}End Set{4}" _
& "{6}End Property{4}{4}"
repPatternReadOnly = "{6}Private {2}ReadOnly m_{0} As {1}{3}{4}" _
& "{6}Public ReadOnly {2}Property {0}() As {1}{4}" _
& "{6}{5}Get{4}" _
& "{6}{5}{5}Return m_{0}{4}" _
& "{6}{5}End Get{4}" _
& "{6}End Property{4}{4}"
ElseIf docName.EndsWith(".cs") Then
' Notice the (?.*;) element is needed to ensure that public fields are matched,
' but public properties aren't
findPattern = "(?<indent>[\t ]+)public\s+(?<static>static\s+)?(?<readonly>readonly\s+)?" _
"(?<type>\S+)\s+(?<name>\w+)(?=.*;)(?<init>.*?)\n"
' {0}=property name, {1}=property type, {2}=static keyword, {3} initvalue,
' {4}=CR-LF, {5}=Tab, {6}=indent
repPattern = "{6}private {2}{1} m_{0}{3}{4}" _
& "{6}public {2}{1} {0}{4}" _
& "{6}{{{4}" _
& "{6}{5}get {{ return m_{0}; }}{4}" _
& "{6}{5}set {{ m_{0} = value; }}{4}" _
& "{6}}}{4}{4}"
repPatternReadOnly = "{6}private {2}readonly {1} m_{0}{3}{4}" _
& "{6}public {2}{1} {0}{4}" _
& "{6}{{{4}" _
& "{6}{5}get {{ return m_{0}; }}{4}" _
& "{6}}}{4}{4}"
End If
' Replace the text. Add a trailing CR-LF but remove it later.
Dim replaceText As String = Regex.Replace(text + ControlChars.CrLf, findPattern, _
AddressOf ReplaceWithProperty)
ed1.ReplaceText(ed2, replaceText.Substring(0, replaceText.Length - 2), 0)
End Sub
' Private callback function for the Replace method
Private Function ReplaceWithProperty(ByVal m As Match) As String
Dim pattern As String = repPattern
If m.Groups("readonly").Length > 0 Then pattern = repPatternReadOnly
Return String.Format(pattern, m.Groups("name").Value, m.Groups("type").Value, _
m.Groups("static").Value, m.Groups("init").Value, ControlChars.CrLf, _
ControlChars.Tab, m.Groups("indent").Value)
End Function
End
Module
Thanks to regular expressions, and in spite of the low amount of code it contains, this macro works both in VB and C#, it enables you to convert multiple fields in one shot, it preserves the field's initial value and even its static/Shared and Readonly attributes, and it also preserves any statement between variable declarations. In practice, therefore, you can just select the source code of an entire class and convert all its public fields into properties, with just a mouse click! 
For each property, the macro creates a variable named m_PropertyName; obviously you can use your favorite naming convention by editing the statement that assigns regPattern. C# developers can edit the code to generate multi-lined get/set blocks. (I prefer to have more compact blocks.)