Search code examples
powershellautomationresharperassembly-references

C#: Automated removal of unnecessary assembly references?


I'm working with a large code base with a huge number of projects, each of which has a handful (and in some cases, enormous) amount of references to others. There has been substantial refactoring done on this codebase over time, and as a result there are many assemblies that are referenced by some projects only because they used to contain a class that has since moved elsewhere; that sort of thing.

ReSharper has a tool integrated into the IDE that allows users to find code that actually uses a given reference for a given project, however in order to turn this into a solution we would need to get a person to right click on every reference in every project and then to actually check for no usages and then delete them, which is not only a long process but also it borders on torture.

I would like to be able to automate this process so that we just run it and unnecessary references are removed; we could then perhaps integrate it into some sort of regular process so that overlooked mistakes would be caught.

The two options I've thought of would be A) Automate ReSharper with Powershell, if possible, or B) perhaps Visual Studio 2010 Architecture dependency diagrams could handle this, and maybe in a scriptable way if I'm lucky.

My questions are these:

  • Can ReSharper be scripted for something like this?
  • Does VS2010 Architecture provide for removal of unused references in any sort of batch/automated way?

Solution

  • You should be able to do this with just plain powershell:

    1) load visual studio with your solution

    2) compile entire solution

    3) leave VS running and start powershell.exe

    4) grab a reference to the still running instance of VS's DTE from the ROT (important - ensure only one instance running - if its elevated, powershell should be too):

    ps> $dte = [System.Runtime.InteropServices.Marshal]::GetActiveObject("visualstudio.dte")
    

    5) Test by enumerating all projects in the solution with their references:

    ps> $dte.solution.projects | select @{l="name";e={$_.name}}, `
            @{l="references";e={$_.object.references|select -exp name}} | ft -auto
    

    ... dumps all project names and references ...

    6) Now, write some script to traverse the solution folder and projects

    7) when you hit the bin\ folder, load up the assembly with reflection only load:

    $assembly = [reflection.assembly]::reflectiononlyload($dll)
    

    8) get the actual referenced assemblies in your output assembly

    $refs = $assembly.getreferencedassemblies()
    

    9) compare the actual referenced assemblies to the assemblies referenced in the project and remove the redundant ones via the VS DTE object model

    # example
    $currentproj.object.references.item("system.core").remove()
    $currentproj.save()
    

    10) profit!

    This works because .net only links assemblies that are actually referenced in the code. Sorry I can't post a full working example but this should be enough to get you started.

    -Oisin