Refactoring C# with PowerShell
Visual 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 }
January 6th, 2008 at 3:47 pm
Heheh, I done similar source code mods like this. One addition that you might consider is using Write-Progress to keep you updated on the progress of the script since this type of operation could take a while depending on the size of your codebase.
January 6th, 2008 at 3:50 pm
You know, I could’ve sworn I had that in there – I think I might’ve updated the script for our use after I wrote the blog post. I’ll update it if that’s the case (Monday, of course – now is the time for Guitar Hero 3
)
January 6th, 2008 at 8:24 pm
[...] 6, 2008 Posted in January 6th, 2008 by Alvin Ashcraft in Daily Links, Development, microsoft Refactoring C# with PowerShell (via Jason [...]
January 8th, 2008 at 12:03 am
[...] Refactoring C# with PowerShell – Aaron Lerch details an interesting use of Powershell – Makes DOS batch files look very antiquated. [...]