扩展方法的SymbolInfo

Ser*_*046 10 .net c# roslyn

我需要分析一些扩展方法.例如Enumerable.ToList.

要分析的代码示例:

var test = @"
using System.Linq;

namespace Test
{
    public class TestType
    {
        void TestMethod()
        {
            var empty = new[] {0};
            var test = empty.ToList();
        }
    }
}";
Run Code Online (Sandbox Code Playgroud)

诊断:

public override void Initialize(AnalysisContext context)
{
    context.RegisterSyntaxNodeAction(AnalyzeSymbol, SyntaxKind.InvocationExpression);
}

private static void AnalyzeSymbol(SyntaxNodeAnalysisContext context)
{
    var symbolInfo = context.SemanticModel.GetSymbolInfo(context.Node);
}
Run Code Online (Sandbox Code Playgroud)

但是symbolInfo.Symbol无效且没有任何候选人.如果我像这样更改代码示例:

var test = @"
using System.Linq;

namespace Test
{
    public class TestType
    {
        void TestMethod()
        {
            var empty = new[] {0};
            var test = Enumerable.ToList(empty);
        }
    }
}";
Run Code Online (Sandbox Code Playgroud)

然后symbolInfo有一个候选人,但仍然没有符号.如何获取扩展方法调用的符号信息?

dym*_*oid 5

如果您使用的是从“带有代码修复的分析器”项目模板自动创建的默认单元测试帮助程序类,那么您应该注意以下事项。

GetSortedDiagnosticsFromDocuments即使在处理您作为输入提供的代码时出现编译错误,该方法也会尝试运行分析器。当然,当出现编译错误时,语义模型可能不完整或缺失。

您可以通过以下方式更改此方法:

// old version: no compilation errors detection
var compilationWithAnalyzers = project.GetCompilationAsync().Result.WithAnalyzers(ImmutableArray.Create(analyzer));


// new version: detect the compilation errors
var compilation = project.GetCompilationAsync().Result;             
var compilerErrors = compilation.GetDiagnostics().Where(i => i.Severity == DiagnosticSeverity.Error);

if (compilerErrors.Any())
{
    return compilerErrors.ToArray();
}

var compilationWithAnalyzers = compilation.WithAnalyzers(ImmutableArray.Create(analyzer));
Run Code Online (Sandbox Code Playgroud)

如果您随后尝试使用此代码和输入字符串运行单元测试,您将注意到至少 2 个编译错误:

错误 CS0012:类型“List<>”是在未引用的程序集中定义的。您必须添加对程序集“System.Collections, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”的引用。

(版本号可能不同)

错误 CS5001:程序不包含适合入口点的静态“Main”方法

您需要解决这些错误才能编译您的代码,以便您可以访问有效的语义模型。

  • 将您的更改void TestMethod()static void Main(). 这并不是真正必要的,但最好有一个没有编译器错误的有效代码。
  • 添加一个引用到System.CollectionsSystem.Runtime你的动态生成的项目。当您使用项目模板中的帮助程序代码时,在单元测试中没有方便的方法来执行此操作。但是要测试它,您可以更改CreateProject方法。

默认情况下,配置了 4 个附加引用。添加缺少的引用:

var collectionsReference = MetadataReference.CreateFromFile(typeof(Stack<>).Assembly.Location);
var runtimeReference = MetadataReference.CreateFromFile(typeof(ISet<>).Assembly.Location);

var solution = new AdhocWorkspace()
    .CurrentSolution
    .AddProject(projectId, TestProjectName, TestProjectName, language)
    .AddMetadataReference() //...
    // ...extend the AddMetadataReference chain
    .AddMetadataReference(projectId, collectionsReference)
    .AddMetadataReference(projectId, runtimeReference);
Run Code Online (Sandbox Code Playgroud)

然后,您应该能够在单元测试中编译代码并获得有效的语义模型。

您可能愿意实现动态引用功能,例如通过将正在创建的项目对象公开给单元测试调用者。