Friday, January 04, 2008 6:06 PM alerch

Refactoring C# with PowerShell

imageVisual Studio 2005 and 2008 have built-in support for refactoring code, including renaming namespaces, classes, variables, and more. Add-ins like Resharper also have support for refactoring by renaming. These tools work great, and have good integration into the Visual Studio IDE, for example being able to preview each change and exclude false positive matches. I know many people swear by Resharper in particular (for more features than the refactoring alone).

Unfortunately all of these tools are restricted in one normally insignificant way: they only operate on the currently loaded project(s). For most software this really is insignificant. The entire application can be loaded into the IDE all at once. Sometimes, though, it is a problem--usually when there's another problem at play: code "bloat" (via Jeff).

If you've ever changed a namespace and wanted to simply push the change into every code file in an entire directory branch, PowerShell comes to our rescue with it's search-and-replace capabilities. I wrote the following "Move-Namespace" function to do just that.

Invoke the function like so: "Move-Namespace *.cs "[current namespace]" "[current class name]" "[new namespace]".

After it completes, any explicit reference will be changed, and any implicit references (using traditional "using [namespace];" statements) will have a new "using [new namespace];" line inserted after the last existing using statement.

Let's hope you don't have a code base that requires this function. :) But if you do, I hope it helps!

Note that this function relies on my "Replace-String" function, found here.

function Move-Namespace(
    $includes = $(throw 'Specify a file filter to use'), 
    $oldNamespace = $(throw 'The namespace to replace - i.e. MyCompany.Product'), 
    $className = $(throw 'The class name to search for - i.e. MyClass'), 
    $newNamespace = $(throw 'The new namespace to add - i.e. MyCompany.Product.Feature'))
{    
    # Look for cases of $className
    # or $oldNamespace.$className
    # and replace as necessary
    
    # First check for assumed "using" statements, and add the using statement
    $results = @{}
    $files = get-childitem -r -i $includes | select-string "(?<!$oldNamespace\.)\b$className\b" -list |% { $_.Path }
    select-string "^using.*;" -path $files | group-object Path | select-object Name, @{Expression={ ($_.Group | measure-object -property LineNumber -max).Maximum }; Name="LastUsingStatement" } |% { $results[$_.Name] = $_.LastUsingStatement }
    foreach ($key in $results.keys)
    {
      $processFile = $true
      $lastUsingIndex = $results[$key]
      $fileContents = get-content $key
      # look for existing using statement and cancel processing this file
      for ($i = 0; $i -lt $lastUsingIndex; $i++)
      {
        if ($fileContents[$i] -match "using $newNamespace;")
        {
          # this file already has the correct using statement, stop processing
          Write-Warning "File $key already has the required using statement, ignoring"
          $processFile = $false
          break;
        }
      }
      
      if ($processFile)
      {
        $newContents = $fileContents[0..($lastUsingIndex-1)] + "using $newNamespace;" + $fileContents[$lastUsingIndex..$fileContents.Length]
        set-content -path $key -value $newContents
        Write-Host "Successfully updated file $key" -foregroundcolor Green
      }
    }
    
    # Next check for explicit references
    replace-string "\b$oldNamespace\.$className\b" "$newNamespace.$className" $includes
}

Comments

# re: Refactoring C# with PowerShell

Saturday, January 05, 2008 7:41 AM by kotły c.o.

Really nice part of code!

Do you know any repositories for another functions like this one?

# re: Refactoring C# with PowerShell

Saturday, January 05, 2008 10:54 AM by alerch

Other than the scripts found on the MS Script Center (www.microsoft.com/.../default.mspx) which are typically not related to manipulating code/strings and more aligned with systems management, I don't, sorry!

You might find something useful in my "Powershell" category on my blog? Who knows :)

www.aaronlerch.com/.../powershell

# Finds of the Week - January 6, 2008 &raquo; Chinh Do

Monday, January 07, 2008 1:40 AM by Finds of the Week - January 6, 2008 » Chinh Do

Pingback from  Finds of the Week - January 6, 2008 &raquo; Chinh Do

Leave a Comment

(required) 
(required) 
(optional)
(required)