我正在开发一个应用程序,用于检测并消除给定 C# 项目中无用的外部引用,例如引用但未使用的包。为此,我需要枚举在编译和运行时使用的所有程序集。对于那些在运行时使用的,我可以使用反射专门调用Assembly.GetReferencedAssemblies()
. 但是对于那些仅在编译时使用的,我认为没有使用 Roslyn 就无法列出它们。请问您对我的问题有任何答案吗?
1 回答
这只是一种简单的方法,远非完美。我相信你可以更深入地和 Roslyn 一起玩。我也确信那里有比我更好的编译器和 Roslyn 专家:)
请注意,此方法不处理动态加载的程序集。它避免了运行项目。
引用的程序集
您可以使用 XML 解析器而不是 Roslyn 来分析项目或解决方案文件。在那里你会找到所有引用的包和项目的列表,例如:
<ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="MessagePack" Version="2.1.115" />
</ItemGroup>
上面的示例来自一个 .NET Core 3.1 项目文件。
更新
为了收集传递依赖,还有几个选项。
对于 .NET Core 项目,您可以调用
dotnet restore
并阅读以下文件$ProjectFolder/obj/project.assets.json
。它是一个 json 文件,其中包含已解析的所有引用,其中包含 NuGet 和运行时包。如果您想避免恢复项目/解决方案,您可以从
.csproj
如上所述找到的包开始,并使用NuGet Server API获取每个依赖项的数组。递归执行此操作将产生与 相同的结果dotnet restore
。NuGet Core将 API 包装为 C# 类,因此您可以直接从代码中调用它。可以像这里一样轻松查询依赖项:如何从私有 NuGet 源获取 NuGet 包的依赖项?
所需的组件
现在你需要确定那些真正需要的。编译过程会处理这个问题。它不会(据我所知)在编译的代码中插入任何不必要的引用。
Roslyn 语义模型
在这个问题中解决:Roslyn getting dependencies for class
IL 选项
您可以使用 Roslyn 编译给定项目,然后加载生成的 IL 并查找类似[System.Private.CoreLib]
. HashSet
一旦在 IL 中找到匹配的调用,只需将所有引用的程序集放入 a并删除它们。结果集将包含可以删除的引用。
也许这个项目可以帮助查看 IL。当您需要 Roslyn 输出示例时,SharpLab也非常方便。
加载选项
如果您可以加载已编译的项目,则可以Assembly.GetReferencedAssemblies()
按照问题中的指示使用,而不是分析 IL。