C#:自动删除不必要的程序集引用?

时间:2011-01-28 18:37:15

标签: powershell automation resharper assembly-references

我正在使用一个包含大量项目的大型代码库,每个项目都有少量(在某些情况下,巨大的)引用其他项目。随着时间的推移,在这个代码库上已经进行了大量的重构,因此有些项目被一些项目引用只是因为它们曾经包含一个已移到别处的类;那种事。

ReSharper在IDE中集成了一个工具,允许用户查找实际使用给定项目的给定引用的代码,但是为了将其转换为解决方案,我们需要让人员右键单击每个引用在每个项目中,然后实际检查没有使用,然后删除它们,这不仅是一个漫长的过程,而且还与酷刑接壤。

我希望能够自动执行此过程,以便我们只运行它并删除不必要的引用;然后我们可以将它整合到某种常规过程中,以便捕获被忽视的错误。

我想到的两个选项是A)如果可能的话,使用Powershell自动化ReSharper,或者B)也许Visual Studio 2010架构依赖关系图可以处理这个问题,如果我很幸运,也许可以用脚本方式。< / p>

我的问题是这些:

  • ReSharper能为这样的东西编写脚本吗?
  • VS2010架构是否可以以任何批量/自动方式删除未使用的引用?

3 个答案:

答案 0 :(得分:6)

你应该能够通过简单的PowerShell来做到这一点:

1)使用您的解决方案加载visual studio

2)编译整个解决方案

3)让VS运行并启动powershell.exe

4)从ROT获取对仍然运行的VS DTE实例的引用(重要 - 确保只运行一个实例 - 如果它的提升,powershell也应该这样):

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

5)通过枚举解决方案中的所有项目进行测试:

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

...转储所有项目名称和引用......

6)现在,编写一些脚本来遍历解决方案文件夹和项目

7)当您点击bin \文件夹时,仅使用反射加载程序集:

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

8)在输出程序集中获取实际引用的程序集

$refs = $assembly.getreferencedassemblies()

9)将实际引用的程序集与项目中引用的程序集进行比较,并通过VS DTE对象模型删除冗余的程序集

# example
$currentproj.object.references.item("system.core").remove()
$currentproj.save()
10)利润!

这是有效的,因为.net只链接代码中实际引用的程序集。对不起,我无法发布一个完整的工作示例,但这应该足以让您入门。

-Oisin

答案 1 :(得分:1)

不是完整的解决方案,但请查看Resolve csproj dependencies when projects are dependent on assemblies from bin as wellHow to find wrong assembly dependencies via PowerShell。有一种方法可以找到其他项目的参考资料以及如何在集会中找到参考资料。

第二部分与Oisin提出的相同。第一个略有不同 - 它从csproj文件中获取引用(作为xml文件并以这种方式处理)。

至少作为灵感;)

答案 2 :(得分:1)

我按照@ x0n的说明操作,但对我来说效果不佳。也许我错过了什么。我必须承认,由于COM错误,我无法使用dll加载ReflectionOnlyLoad s。所以我用LoadFile加载它们。当我使用Reflector加载Assembly时,LoadFile提供的程序集引用完全相同。最后,我的PowerShell脚本生成了一个列表,显示了项目中但未由程序集加载的引用。从理论上讲,这些应该是“不必要的”参考。当我开始删除它们时,构建失败。例如,在我的第一个项目中,缺少任何4个“不必要的”引用将导致构建失败。我浏览了powershell脚本的输出,它也列出了“System”。如果我删除它,编译器甚至不会抱怨一堆“using System;”但它在此之前失败 - 说明我需要引用该程序集因为接口... 顺便说一句,我们的项目不是一个玩具,它涉及140多个dll(其中几乎一半是测试nUnit dll),我想我会做一些houskeeping。 我的脚本(不会递归到项目文件夹 - 一些项目包含更多dll)所以也许有人可以使用它:

`
    $ dte = [System.Runtime.InteropServices.Marshal] :: GetActiveObject(“visualstudio.dte”)

$binfiles=Get-ChildItem C:\YourSourcePath\bin\debug
$dlls=$binfiles | where { $_.extension -eq ".dll" -and $_.name -like "*YourCompanyName*" }

foreach ($dll in $dlls) {
    foreach($prj in $dte.solution.projects) {
        if ($prj.Kind -eq "{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") {
            if ($prj.Properties.Item("OutputFileName").Value -eq $dll.Name) {
                $loaded = [reflection.assembly]::LoadFile($dll.FullName)
                $refs = $loaded.GetReferencedAssemblies()
                Write "============="
                Write $dll.Name
                Write "-------------"
                foreach($pref in $prj.Object.References) {
                    $found = 0
                    foreach($ref in $refs) {
                        if ($ref.Name -eq $pref.Name) {
                            $found = 1
                            break;
                        }
                    }
                    if ($found -eq 0) {
                        Write $pref.Name
                    }
                }
            }
        }
    }
}

`