VS2005マクロ(プロパティー一括生成)

VS2005マクロ(プロパティー一括生成)を書いてみた。

Eclipseを使っていたときお世話になった機能「GetterおよびSetterの生成」がVisualStudio2005になかったっぽいので作ってみました。

マクロがVC++6の頃とは随分変わってしまい困りましたがなんとかできました。

以下の行を選択してマクロを実行すると

    Private _foo As String = ""
    Private _bar As Integer = 0

以下のようにプロパティーが一括生成されます

    Private _foo As String = ""
    ''' <summary>
    ''' 
    ''' </summary>
    Public Property Foo() As String
        Get
            Return _foo
        End Get
        Set(ByVal value As String)
            _foo = value
        End Set
    End Property

    Private _bar As Integer = 0
    ''' <summary>
    ''' 
    ''' </summary>
    Public Property Bar() As Integer
        Get
            Return _bar
        End Get
        Set(ByVal value As Integer)
            _bar = value
        End Set
    End Property

参考にしたマクロ

  • VisualStudio2005のサンプルマクロ(「DevStudio6Editor」がVC++6のマクロを移植したものなので参考になります。)
  • VisualStudio2005のサンプルマクロ (Utilitiesの「InsertDocComments」)


C#とBasicに対応しています。(VisualStudio.NET2003は確認してません)

#Region "変数からプロパティーを生成"
     ' 選択範囲の変数からプロパティーを生成する(VB.NET、C#対応)
     ' 既に同名のプロパティーがあれば作成しない
     ' 
     ' プロパティー名の規則
     ' 1:変数は"_"(アンダースコア)から始まること
     ' 2:プロパティー名は変数の先頭1文字を削除し、次の文字を大文字に変換した名前とする
     '   (ex. 「_foo 」→「Foo」)
     Sub MakeProperty()
         ' 現在の選択範囲
         Dim sel As EnvDTE.TextSelection = DTE.ActiveDocument.Selection
         Dim selTop As VirtualPoint = sel.TopPoint
         Dim selBottom As VirtualPoint = sel.BottomPoint
         ' もし下から上へ選択している場合は、選択範囲を交換する
         If selTop.Line = DTE.ActiveDocument.Selection.ActivePoint.Line Then
             sel.SwapAnchor()
         End If
 
         Dim actPoint As TextPoint = DTE.ActiveDocument.Selection.ActivePoint
         ' 現在キャレットがある場所のクラスを取得
         Dim elm As CodeElement = actPoint.CodeElement(vsCMElement.vsCMElementClass)
         Dim cls As CodeClass = elm
         Dim typ As CodeType = CType(elm, CodeType)
 
         'クラス内に既に存在するプロパティー一覧を作成する(重複作成しないためのチェック用)
         Dim lstProp As New System.Collections.Generic.List(Of String)
         For Each ite As CodeElement In typ.Members
             If TypeOf ite Is CodeProperty Then
                 lstProp.Add(ite.Name)
             End If
         Next
 
         ' 編集用オブジェクト
         Dim editPoint As EditPoint
         Dim sbProp As New Text.StringBuilder
 
         ' クラス内のメンバーに対して
         For Each ite As CodeElement In typ.Members
             sbProp.Length = 0
 
             ' 変数であるかチェック
             If Not TypeOf ite Is CodeVariable Then
                 Continue For
             End If
 
             ' 変数が選択範囲内かチェック
             Dim elmVal As CodeVariable = DirectCast(ite, CodeVariable)
             Dim valLine As Integer = elmVal.StartPoint.Line
             If Not (selTop.Line <= valLine AndAlso valLine <= selBottom.Line) Then
                 Continue For
             End If
 
             ' 変数名の先頭がアンダースコアであるかチェック
             If elmVal.Name.Substring(0, 1) <> "_" Then
                 Continue For
             End If
 
             ' 同じ名前のプロパティーが存在している場合は作成しない
             If lstProp.Contains(GetPropNm(elmVal.Name)) Then
                 Continue For
             End If
 
             ' プロパティー文字列を生成する
             If DTE.ActiveDocument.Language = "Basic" Then
                 ' 編集中ファイルがVBの場合
                 sbProp.AppendFormat("''' <summary>").AppendLine()
                 sbProp.AppendFormat("''' ").AppendLine()
                 sbProp.AppendFormat("''' </summary>").AppendLine()
                 sbProp.AppendFormat("Public Property {0}() As {1}", GetPropNm(elmVal.Name), elmVal.Type.AsString).AppendLine()
                 sbProp.AppendFormat("    Get").AppendLine()
                 sbProp.AppendFormat("        Return {0}", elmVal.Name).AppendLine()
                 sbProp.AppendFormat("    End Get").AppendLine()
                 sbProp.AppendFormat("    Set(ByVal value As {0})", elmVal.Type.AsString).AppendLine()
                 sbProp.AppendFormat("        {0} = value", elmVal.Name).AppendLine()
                 sbProp.AppendFormat("    End Set").AppendLine()
                 sbProp.AppendFormat("End Property").AppendLine()
             ElseIf DTE.ActiveDocument.Language = "CSharp" Then
                 ' 編集中ファイルがC#の場合
                 sbProp.AppendFormat("/// <summary>").AppendLine()
                 sbProp.AppendFormat("/// ").AppendLine()
                 sbProp.AppendFormat("/// </summary>").AppendLine()
                 sbProp.AppendFormat("public {0} {1}", elmVal.Type.AsString, GetPropNm(elmVal.Name)).AppendLine()
                 sbProp.AppendFormat("{{").AppendLine()
                 sbProp.AppendFormat("        get {{ return {0}; }}", elmVal.Name).AppendLine()
                 sbProp.AppendFormat("        set {{ {0} = value; }}", elmVal.Name).AppendLine()
                 sbProp.AppendFormat("}}").AppendLine()
             End If
 
             ' 変数の次の行にプロパティーを追加する
             editPoint = elmVal.GetEndPoint().CreateEditPoint()
             editPoint.Insert(System.Environment.NewLine)
             editPoint.Insert(sbProp.ToString)
         Next
         ' プロパティーのフォーマットを行う
         sel.LineDown(True, 12)
         sel.SmartFormat()
         sel.LineUp(False)
     End Sub
 
     ' 変数名からプロパティー名を生成して返す
     Private Function GetPropNm(ByVal varNm As String) As String
         Dim nm As String = varNm.Substring(1)
         Return nm.Substring(0, 1).ToUpper() & nm.Substring(1)
     End Function
 
 #End Region