KnowDotNet NetRefactor

Using the FileCodeModel to Get the Code for a Method

Used in Conject with the CodeModel Object

by Les Smith
Print this Article Discuss in Forums

Using the CodeModel object, you can explore a project or solution in Visual Studio .NET.  The projects can be VB.NET or CSharp (C#), and can be mixed and the CodeModel object can be used to explore them.  Given that you have retrieved a desired method name and its length from using th CodeModel object, how can you fetch the code for that method?

The GetCodeForMethod, shown below, assumes that you have retrieved a ProjectItem and starting and ending line numbers by using the CodeModel object.  These parameters are passed into the method.  The method returns a string which contains the code, along with any comments that precede the code for the method.

This code will retrieve code from a C# or VB CodeClass.  C# code will always have a Namespace.  The VB Class can be with or without Namespaces.  

Since the method is lengty, I will document the code with in-line comments rather than trying to describe it from outside of the method.

   Function GetCodeForMethod(ByRef roPI As ProjectItem, _
      
ByVal iStPt As Integer, _
      
Optional ByVal iEndPt As Integer = 1) _
      
As String
      ' returns code for a module which is pointed
      ' to by projectitem, start and end pts.
      ' handles VB and C#, with/without namespaces.
      Dim pi As ProjectItem = roPI
      
Dim filecm As FileCodeModel = pi.FileCodeModel
      
Dim ce As CodeElement
      
Dim i As Integer

      Try
        
' If there are no codeelements in the projectitem, exit
         ' leaving the string empty...

         If filecm.CodeElements.Count = 0 Then return String.Empty

        
' a code module or class consists of code elements, which
         ' are methods, variables, namespaces, etc.

         For Each ce In filecm.CodeElements
            
' first, check to see if we have a namespace wrapping
            ' one or more classes

            
If ce.Kind = vsCMElement.vsCMElementNamespace Then
               Dim cns As CodeNamespace = ce
              
Dim cl As CodeClass
              
' a namespace can have one or more classes
              
For Each cl In cns.Members
                  
Dim cetype As CodeType = CType(cl, CodeType)
                  
' the editpoint object is used to walk thru the
                  ' code buffer that lives behind text window,
                  ' regardless of whether the window is open or not
                  ' here we move to the begining of the code element
                  Dim ep As EditPoint = _
                     cetype.GetStartPoint _
                     (vsCMPart.vsCMPartHeader).CreateEditPoint
                  
Dim sTextLine As String
                  Dim sb As New Text.StringBuilder()
                  ep.MoveToLineAndOffset(iStPt, 1)
                  
' back up to previous line looking for
                  ' preceding comments
                  Do
                     ep.LineUp()
                     iStPt -= 1
                     iEndPt += 1
                     sTextLine = ep.GetText(ep.LineLength)
                    
If sTextLine.Trim.Length = 0 OrElse _
                        (
Not sTextLine.trim.StartsWith("'") And _
                        
Not stextline.Trim.StartsWith("/")) Then
                        ep.LineDown()
                        iStPt += 1
                        iEndPt -= 1
                        
Exit Do
                     End If
                  Loop

                  ' loop to get all lines in the method
                  ' use for instead of do so c# will work
                  For i = 1 To iEndPt 'Do
                     sTextLine = ep.GetText(ep.LineLength)
                     sb.Append(sTextLine & vbCrLf)
                     ep.LineDown()
                  
Next i 'Loop
                  Return sb.ToString
              
Next
            Else
               ' first, check to see if we have a namespace wrapping
               ' one or more classes

              
Dim celt As CodeElement = ce
              
Dim cetype As CodeType = CType(celt, CodeType)
              
' the editpoint object is used to walk thru the
               ' code buffer that lives behind text window,
               ' regardless of whether the window is open or not
               ' here we move to the begining of the code element
               Dim ep As EditPoint = _
                  cetype.GetStartPoint(vsCMPart.vsCMPartHeader) _
                  .CreateEditPoint
              
Dim sTextLine As String
               Dim sb As New Text.StringBuilder()
               ep.MoveToLineAndOffset(iStPt, 1)
              
' back up to previous line looking for
               ' preceding comments
               Do
                  ep.LineUp()
                  iStPt -= 1
                  iEndPt += 1
                  sTextLine = ep.GetText(ep.LineLength)
                  
If sTextLine.Trim.Length = 0 OrElse _
                     (
Not sTextLine.trim.StartsWith("'") And _
                    
Not stextline.Trim.StartsWith("/")) Then
                     ep.LineDown()
                     iStPt += 1
                     iEndPt -= 1
                    
Exit Do
                  End If
               Loop

               ' loop to get all lines in the method
               ' use for instead of do so c# will work
               For i = 1 To iEndPt 'Do
                  sTextLine = ep.GetText(ep.LineLength)
                  sb.Append(sTextLine & vbCrLf)
                  ep.LineDown()
              
Next i 'Loop
               Return sb.ToString
            
End If
         Next
      Catch ex As System.Exception
         MsgBox("Error in CFileCodelModel.GetCodeForMethod: " & ex.Message)
      
End Try
   End Function

Writing Add-Ins for Visual Studio .NET
Writing Add-ins for Visual Studio .NET
by Les Smith
Apress Publishing