![]() |
General Programming »
Macros and Add-ins »
VS.NET Macros
Advanced
Abstract Method / Interface Implementation MacroBy Yaron GolanMacro for auto-implementing abstract methods extended by given class or interfaces. |
VB, .NET, Win2K, WinXP, Visual Studio, Dev
|
|
Advanced Search Add to IE Search |
|
|
|
||||||||||||||||
So... I got pretty sick and tired of re-overriding abstract methods for each class based off an abstract one, and decided to write the following macro so I wouldn't have to do it, ever again :).
Notes:
To install, download the vsmacros ZIP file (above), and extract it into any directory. Then go to Visual Studio .NET, and hit Alt-F8. The Macros window should open up. Select the topmost element ("Macros"), right-click and choose "Load Macro Project...", and then select the file from where you dropped it to. You will now get an element named CodeAssist under the "Macros" parent. Hit "Setup" to have it bind the popup-menus to your Solution and Class View. You're set!
Select a class from your Solution or Class View, right-click and choose "Code-Assist -> Implement Abstract Methods". This will automatically add methods with their respective comments from parent abstract classes and interfaces.
Comments welcome, and encouraged!!!
First off, some functional tools:
checkLanguage - Verifies that a given document is in C#. Otherwise throws exception. ' 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
hasFunction - Verifies if function exists in class (Note - this is still WIP, as it doesn't check overload for same name, different parameters). Will be improved in the future. To perform this, we received a ClassElement (of type CodeClass), and we then retrieve a list of its class members. We then iterate through them and find functions of the same name. Note that we check if the member is a function, by comparing against 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 FunctionNow we start with the nuts and bolts of the whole thing:
processBaseClasses - this piece here will process base classes and interfaces, and add their abstract functions or must-implement methods to the the list of functions to be implemented. First off, it receives a functions ArrayList - note that this function is recursive, and therefore this is the sole container of all the functions which are to be processed later. It also receives the list of base classes and implemented interfaces which a given class contains. These are iterated through and each of their "MustImplement" functions are added to the container (functions), and will then be added to the class itself.
The code contains comments, which will allow for following the code. I will expand on request.
' 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
processBaseClasses, above)
' 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 SubNow this snippet here was quite a challenge to create. I had been searching around for several of the items here until finally I understood the way things worked. I broke it down into 3 main methods:
GetCommandBars - Retrieves command bars for Solution and Class popups.
AddMenu - Removes old submenu items (if exists), and adds new submenu.
AddCommand - Adds given macro command to menu item. Please note bolded line in AddMenu (addCommand) -> points to macro location. It's currently pointing to a project named VisualStudioMacros. If this doesn't make sense to you or you deposit the macros in a different project - please change this.
Imports EnvDTE
Imports System.Diagnostics
Imports System.IO
Imports System.Text
Imports System.Collections
Imports Microsoft.Office.CorePublic 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
That's it!
| You must Sign In to use this message board. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||
General
News
Question
Answer
Joke
Rant
Admin
|
PermaLink |
Privacy |
Terms of Use
Last Updated: 9 Jun 2003 Editor: Smitha Vijayan |
Copyright 2003 by Yaron Golan Everything else Copyright © CodeProject, 1999-2009 Web17 | Advertise on the Code Project |