.NET 编译器平台(也称为“Roslyn”)允许开发人员创建 分析器 ,以在编写代码时检查语法树和代码语义。 这为开发人员提供了创建特定于域的分析工具的方法,例如有助于指导特定 API 或库使用的分析工具。 可以在 .NET/Roslyn GitHub Wiki 上找到详细信息。 另请参阅 MSDN 杂志上的文章:《使用 Roslyn 为您的 API 编写实时代码分析器》。
分析器本身通常打包和分发,作为实现 API 或库的 NuGet 包的一部分。
有关一个很好的示例,请参阅 System.Runtime.Analyzers 包,其中包含以下内容:
- 分析器\dotnet\System.Runtime.Analyzers.dll
- 分析器\dotnet\cs\System.Runtime.CSharp.Analyzers.dll
- 分析器\dotnet\vb\System.Runtime.VisualBasic.Analyzers.dll
- build\System.Runtime.Analyzers.Common.props
- build\System.Runtime.Analyzers.props
- build\System.Runtime.CSharp.Analyzers.props
- build\System.Runtime.VisualBasic.Analyzers.props
- 工具\install.ps1
- 工具\uninstall.ps1
可以看到,将分析器 DLL 放入包中的文件夹中 analyzers 。
包含用于禁用旧 FxCop 规则以采用分析器实现的 Props 文件被放置在 build 文件夹中。
安装和卸载支持使用packages.config项目的脚本被放置在tools。
另请注意,由于此包没有特定于平台的要求, platform 因此省略该文件夹。
分析器路径格式
文件夹 analyzers 的使用类似于用于 目标框架的文件夹,区别在于路径中的说明符描述的是开发主机依赖项,而不是构建时间依赖项。 常规格式如下所示:
$/analyzers/{framework_name}{version}/{supported_architecture}/{supported_language}/{analyzer_name}.dll
-
framework_name 和 版本:包含 DLL 需要运行的 .NET Framework 的 可选 API 外围应用。
dotnet目前是唯一有效的值,因为 Roslyn 是唯一可以运行分析器的主机。 如果未指定任何目标,则假定 DLL 适用于所有目标 。 -
supported_language:DLL 适用的语言,其中一种
cs(C#)和vb(Visual Basic)和fs(F#)。 该语言指示只应为使用该语言的项目加载分析器。 如果未指定任何语言,则假定 DLL 适用于支持分析器 的所有 语言。 - analyzer_name:指定分析器的 DLL。 如果需要 DLL 以外的其他文件,则必须通过目标或属性文件包含这些文件。
安装和卸载脚本
如果用户的项目正在使用 packages.config,则选取分析器的 MSBuild 脚本不会发挥作用,因此应放置 install.ps1 并 uninstall.ps1 放入 tools 文件夹中,其中包含下面所述的内容。
install.ps1 文件内容
param($installPath, $toolsPath, $package, $project)
$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" ) * -Resolve
foreach($analyzersPath in $analyzersPaths)
{
# Install the language agnostic analyzers.
if (Test-Path $analyzersPath)
{
foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll)
{
if($project.Object.AnalyzerReferences)
{
$project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)
}
}
}
}
$project.Type # gives the language name like (C# or VB.NET)
$languageFolder = ""
if($project.Type -eq "C#")
{
$languageFolder = "cs"
}
if($project.Type -eq "VB.NET")
{
$languageFolder = "vb"
}
if($languageFolder -eq "")
{
return
}
foreach($analyzersPath in $analyzersPaths)
{
# Install language specific analyzers.
$languageAnalyzersPath = join-path $analyzersPath $languageFolder
if (Test-Path $languageAnalyzersPath)
{
foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll)
{
if($project.Object.AnalyzerReferences)
{
$project.Object.AnalyzerReferences.Add($analyzerFilePath.FullName)
}
}
}
}
uninstall.ps1 文件内容
param($installPath, $toolsPath, $package, $project)
$analyzersPaths = Join-Path (Join-Path (Split-Path -Path $toolsPath -Parent) "analyzers" ) * -Resolve
foreach($analyzersPath in $analyzersPaths)
{
# Uninstall the language agnostic analyzers.
if (Test-Path $analyzersPath)
{
foreach ($analyzerFilePath in Get-ChildItem $analyzersPath -Filter *.dll)
{
if($project.Object.AnalyzerReferences)
{
$project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName)
}
}
}
}
$project.Type # gives the language name like (C# or VB.NET)
$languageFolder = ""
if($project.Type -eq "C#")
{
$languageFolder = "cs"
}
if($project.Type -eq "VB.NET")
{
$languageFolder = "vb"
}
if($languageFolder -eq "")
{
return
}
foreach($analyzersPath in $analyzersPaths)
{
# Uninstall language specific analyzers.
$languageAnalyzersPath = join-path $analyzersPath $languageFolder
if (Test-Path $languageAnalyzersPath)
{
foreach ($analyzerFilePath in Get-ChildItem $languageAnalyzersPath -Filter *.dll)
{
if($project.Object.AnalyzerReferences)
{
try
{
$project.Object.AnalyzerReferences.Remove($analyzerFilePath.FullName)
}
catch
{
}
}
}
}
}