65.9K
CodeProject 正在变化。 阅读更多。
Home

抽象方法/接口实现宏

starIconstarIcon
emptyStarIcon
starIcon
emptyStarIconemptyStarIcon

2.71/5 (7投票s)

2003年6月2日

CPOL

3分钟阅读

viewsIcon

86633

downloadIcon

683

用于自动实现由给定类或接口扩展的抽象方法的宏。

引言

因此... 我厌倦了为每个基于抽象类的类重新覆盖抽象方法,并决定编写以下宏,这样我就不必再这样做了 : )。

注释:

  1. 代码应该具有更好的模块化,并且将来会改进。 如果您想贡献,请联系我 --> yaron@valor.com
  2. 使用 ProjectItem,这意味着它要求您从“类视图”中选择一个项目,然后右键单击它以获取上下文菜单,然后... 好吧,您会掌握它的。
  3. 设置也会自动删除自身,但编写得很糟糕。 但是,它可以完成工作。

安装

要安装,请下载 *vsmacros* ZIP 文件(如上所示),并将其解压缩到任何目录中。 然后转到 Visual Studio .NET,然后按 Alt-F8。 应该打开“宏”窗口。 选择最上面的元素(“宏”),右键单击并选择“加载宏项目...”,然后从您放置它的位置选择文件。 现在,您将在“宏”父项下获得一个名为 *CodeAssist* 的元素。 单击“设置”以将其绑定到您的解决方案和类视图的弹出菜单。 您已设置完毕!

用法

从您的解决方案或类视图中选择一个类,右键单击并选择“代码辅助 -> 实现抽象方法”。 这将自动从父抽象类和接口添加具有各自注释的方法。

欢迎并鼓励评论!!!

代码

首先,一些功能工具

  1. checkLanguage - 验证给定的文档是否为 C#。 否则会抛出异常。
    ' Checks to see that we're using
    ' CSharp (otherwise, this thing WILL fail)
    Private Sub checkLanguage(ByVal document As Document)
        If document.Language <> "CSharp" Then
            Throw New System.Exception("This Macro only works on C# code")
        End If
    End Sub
  2. hasFunction - 验证类中是否存在函数(注意 - 这仍然是 WIP,因为它不检查同名、不同参数的重载)。 将来会改进。 为此,我们接收到一个 ClassElement(类型为 CodeClass),然后检索其类成员的列表。 然后我们遍历它们并找到同名的函数。 请注意,我们通过与 vsCMElementFunction 进行比较来检查成员是否为函数。
    ' Checks to see if function already exists in class
    'TODO: Make this check parameters, as well
    Private Function hasFunction(ByVal classElement As CodeClass, _ 
                                ByVal functionElement As CodeFunction)
        Dim member As CodeElement
        For Each member In classElement.Members
            If (member.Kind = vsCMElement.vsCMElementFunction) Then
                If (member.Name = functionElement.Name) Then
                    Return True
                End If
            End If
        Next
    
        Return False
    End Function

现在我们从整个事物的要点开始

  1. processBaseClasses - 这里的这段代码将处理基类和接口,并将它们的抽象函数或必须实现的方法添加到要实现的函数列表中。 首先,它接收一个函数 ArrayList - 请注意,此函数是递归的,因此这是所有要稍后处理的函数的唯一容器。 它还接收给定类包含的基类和已实现接口的列表。 这些将被遍历,并且它们各自的“MustImplement”函数将被添加到容器(functions)中,然后将被添加到类本身。

    该代码包含注释,可用于跟踪代码。 我会根据要求进行扩展。

    ' Recursively process base classes
    Sub processBaseClasses( _
        ByVal functions As ArrayList, _
        ByVal baseClasses As CodeElements, _
        ByVal implementedInterfaces As CodeElements)
    
        ' Create elements array
        Dim baseElement As CodeElement
    
        ' Collect all items
        Dim elements As ArrayList = New ArrayList()
        For Each baseElement In baseClasses
            elements.Add(baseElement)
        Next
        If (Not implementedInterfaces Is Nothing) Then
            For Each baseElement In implementedInterfaces
                elements.Add(baseElement)
            Next
        End If
    
        ' Exit if done
        If (elements.Count = 0) Then
            Exit Sub
        End If
    
        ' Process base classes
        Dim cFunction As CodeFunction
        For Each baseElement In elements
            Debug.WriteLine(baseElement.Name)
    
            If (baseElement.Kind = vsCMElement.vsCMElementInterface) Then
                ' Recurse
                processBaseClasses( _
                    functions, _
                    baseElement.Bases, _
                    Nothing _
                )
            Else
                ' Recurse
                processBaseClasses( _
                    functions, _
                    baseElement.Bases, _
                    baseElement.ImplementedInterfaces)
            End If
    
            ' Check if this level implements lower ones
            Dim fCnt As Integer = 0
            Do While fCnt < functions.Count
                cFunction = functions.Item(fCnt)
                If (baseElement.Kind = vsCMElement.vsCMElementClass) Then
                    If (hasFunction(baseElement, cFunction)) Then
                            functions.Remove(cFunction)
                    End If
                Else
                    fCnt += 1
                End If
            Loop
    
            ' Get members
            Dim member As CodeElement
            For Each member In baseElement.Members
                If (member.Kind = vsCMElement.vsCMElementFunction) Then
                    cFunction = member
    
                    If (cFunction.MustImplement) Then
                        functions.Add(cFunction)
                    End If
    
                End If
            Next
        Next
    End Sub
  2. 这是单击“实现抽象方法”弹出菜单项时调用的子例程

    1. 它将处理给定文件中的类列表。
      1. 接收要实现的函数列表(参见上面的 processBaseClasses
      2. 将它们添加到当前类。
      ' Impelements abstract methods for class
      Sub ImplementAbstractMethods()
          Try
              ' Life stinks...
              If (DTE.SelectedItems.Count <> 1) Then
                  MsgBox("Function will only work on 1 file")
                  Exit Sub
              End If
      
              ' Get current selection
              Dim currItem As ProjectItem = _
                DTE.SelectedItems.Item(1).ProjectItem
              If (Not currItem.IsOpen) Then
                  currItem.Open()
              End If
      
              Dim currDoc As Document = currItem.Document
      
              ' Check compatibility with language
              CheckLanguage(currDoc)
      
              ' Create arraylist to contain all abstracts items
              Dim functions As ArrayList = New ArrayList()
              Dim cFunction As CodeFunction
      
              ' Get namespace
              Dim fileCM As FileCodeModel = _ 
                currDoc.ProjectItem.FileCodeModel
              Dim cNameSpace As CodeNamespace = _ 
                fileCM.CodeElements.Item(1)
      
              ' Process classes
              Dim classElement As CodeClass
              For Each classElement In cNameSpace.Members
                  processBaseClasses( _
                      functions, _
                      classElement.Bases, _
                      classElement.ImplementedInterfaces _
                  )
      
                  ' Process all members
                  DTE.UndoContext.Open("Add Abstract Implementations")
      
                  For Each cFunction In functions
                      ' Check if exists in class
                      If (Not hasFunction(classElement, cFunction)) Then
                          ' Add function
                          Dim newFunction As CodeFunction
                          Dim type As String = cFunction.Type.AsString
                          If (cFunction.Parent.Kind = _ 
                            vsCMElement.vsCMElementFunction) Then
                              type = "override " + type
                          End If
      
                          ' Create function
                          newFunction = classElement.AddFunction( _
                              cFunction.Name, _
                              vsCMFunction.vsCMFunctionFunction, _
                              cFunction.Type.AsString, _
                              -1, _
                              cFunction.Access _
                          )
      
                          ' Create comment block
                          Dim commentString As String
                          commentString = _
                              "Implementation of " + _ 
                              cFunction.FullName
      
                          ' Add parameters
                          Dim parameter As CodeParameter
                          For Each parameter In cFunction.Parameters
                              newFunction.AddParameter( _
                                  parameter.Name, _
                                  parameter.Type.AsString() _
                              )
      
                              ' Add parameter comment
                              commentString += _
                                      vbCrLf + "<param name=""" _ 
                                      + parameter.Name + _ 
                                      """></param>"
                          Next
      
                          ' now add comment
                          newFunction.Comment = commentString
                      End If
                  Next
      
                  ' Close undo context
                  DTE.UndoContext.Close()
              Next
      
          Catch ex As System.Exception
      
              MsgBox(ex.ToString())
      
          End Try
      
      End Sub

安装脚本(运行一次)

现在,这里的这段代码在创建时面临着相当大的挑战。 我一直在搜索这里的几个项目,直到最后我了解了事物的运作方式。 我将其分解为 3 个主要方法

  1. GetCommandBars - 检索解决方案和类弹出窗口的命令栏。
  2. AddMenu - 删除旧的子菜单项(如果存在),并添加新的子菜单。
  3. AddCommand - 将给定的宏命令添加到菜单项。

请注意 AddMenu (addCommand) 中的粗体行 -> 指向宏位置。 它当前指向一个名为 *VisualStudioMacros* 的项目。 如果这让您感到困惑或者您将宏放置在不同的项目中 - 请更改此设置。

Imports EnvDTE
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Collections
Imports Microsoft.Office.Core
Public Module Setup
    Private Function getCommandBars() As ArrayList
        Dim barList As ArrayList = New ArrayList()

        ' Locate solution and class view popups
        Dim cmdBar As CommandBar
        For Each cmdBar In DTE.CommandBars
            Dim cmdBarCtl As CommandBarControl
            If ((cmdBar.Name = "Item") Or _ 
             (cmdBar.Name = "Class View Item")) Then
                barList.Add(cmdBar)
            End If
        Next

        ' Couldn't find bars
        If (barList.Count = 0) Then
            Throw New _ 
              System.Exception("Failed to locate Popup Menus!")
        End If

        ' return bars
        Return barList
    End Function
    ' This should be run ONLY ONCE
    Private Sub AddMenu()
        Dim menu As CommandBarButton
        Dim cmdBar As CommandBar
        Dim cmdBars As ArrayList
        Dim cmdBarCtl As CommandBarControl

        ' Get command bars
        cmdBars = getCommandBars()

        ' Remove all oldies
        For Each cmdBar In cmdBars
            Dim ctrlCnt As Integer = 1
            While (ctrlCnt <= cmdBar.Controls().Count)
                cmdBarCtl = cmdBar.Controls().Item(ctrlCnt)
                If (cmdBarCtl.Caption.IndexOf("Code-Assist") _
                                              > -1) Then
                    cmdBarCtl.Delete()
                Else
                    ctrlCnt += 1
                End If
            End While

            ' Create menu
            Dim menuPopup As CommandBarPopup
            menuPopup = _ 
             cmdBar.Controls.Add(vsCommandBarType.vsCommandBarTypePopup)
            menuPopup.BeginGroup = True
            menuPopup.Caption = "Code-Assist"

            ' Add commands
            addCommand( _
              "Implement Abstract Methods", _
              "Macros.VisualStudioMacros.Coding.ImplementAbstractMethods", _
              menuPopup _
            )
        Next
    End Sub
    ' Get command to add
    Sub addCommand( _
        ByVal caption As String, _
        ByVal cmdName As String, _
        ByVal menuPopup As CommandBarPopup)

        Dim cmd As Command
        Dim cmdBarCtl As Microsoft.Office.Core.CommandBarControl

        ' Get item
        cmd = DTE.Commands.Item(cmdName)
        ' Add to command bar
        cmdBarCtl = cmd.AddControl(menuPopup.CommandBar())
        cmdBarCtl.Caption = "Implement Abstract Methods"
    End Sub
    ' Sets up menus, ...
    Sub Setup()
        AddMenu()

        MsgBox("Setup done!" & vbNewLine & _ 
           "Check Item menu for Code-Assist entries")
    End Sub

End Module

就是这样!

历史

  • 已更新 -> 6 月 10 日,美国东部时间 9:30
    1. 已将源代码添加到文章中。
    2. 根据要求,现在添加了宏项目 (*.vsmacros*) 的 ZIP 文件。
  • 已更新 -> 6 月 3 日,美国东部时间 9:30
    1. 已修复设置以永久删除菜单项,而不是暂时删除。
    2. 已将菜单项添加到类和解决方案项目视图中。
© . All rights reserved.