【问题标题】:Roslyn CodeFixProvider: Move caret after applying code fixRoslyn CodeFixProvider:应用代码修复后移动插入符号
【发布时间】:2018-03-03 19:01:01
【问题描述】:

我已经实现了一个自定义 CodeFixProvider,它向成员添加了一些 XML 文档。

例子:

public void MyMethod() { }

将转换为

/// <summary></summary>
public void MyMethod() { }

CodeFixProvider 是这样实现的:

public class MyCodeFixProvider : CodeFixProvider
{
  ...

  public async override Task RegisterCodeFixesAsync(CodeFixContext context)
  {
    await Task.Run(() =>
      {
        Diagnostics diagnostics = context.Diagnostics.First();
        CodeAction codeFix = CodeAction.Create("Title", c => CreateXmlDocs(...));

        context.RegisterCodeFix(codeFix, diagnostics);
      }
    ).ConfigureAwait(false);
  }

  ...
}

一切都按预期进行。

现在我想添加一些额外的功能:应用代码修复后,插入符号应该移动到空摘要标记内。

我发现 Microsoft.CodeAnalysis.Features NuGet 包中包含 DocumentNavigationOperation 类。此类应该能够将插入符号移动到指定位置。但我找不到任何说明如何使用这个类。如果我从我的 CreateXmlDocs 方法中调用它,则会引发异常:

Navigation must be performed on the foreground thread.

代码:

private static async Task<Solution> CreateXmlDocs()
{
  ...

  new DocumentNavigationOperation(newDocument.Id, 42)
    .Apply(newDocument.Project.Solution.Workspace, cancellationToken);

  ...
}

我不确定在我的 CreateXmlDocs 方法中使用此类是否有意义,因为在调用 DocumentNavigationOperation 时 Visual Studio 尚未应用在此方法中创建的新解决方案。

有人知道在应用代码修复后移动插入符号的解决方案吗?

【问题讨论】:

  • Roslyn 旨在与 IDE 无关:它可以使用 Visual Studio,但也可以使用命令行。从这个意义上说,在您的代码修复中包含与 IDE 相关的功能就没那么有意义了,因为这是一个环境问题,您可能想要考虑进行扩展。自从我真正与 Roslyn 合作以来已经有一段时间了,但除非情况发生变化,否则这将是你的理由。

标签: c# roslyn codefixprovider


【解决方案1】:

好的,同时我找到了解决方案。

需要自定义 CodeAction 才能使其正常工作:

internal class NavigateAfterCodeChangeAction : CodeAction
{

  private readonly Func<CancellationToken, Task<Solution>> codeChangeOperation;

  private readonly Func<Solution, CancellationToken, Task<NavigationTarget>> navigationTargetCalculation;

  public NavigateAfterCodeChangeAction(
    string title,
    Func<CancellationToken, Task<Solution>> codeChangeOperation,
    Func<Solution, CancellationToken, Task<NavigationTarget>> navigationTargetCalculation)
  {
    this.Title = title;
    this.codeChangeOperation = codeChangeOperation;
    this.navigationTargetCalculation = navigationTargetCalculation;
  }

  public override string Title { get; }

  protected override async Task<IEnumerable<CodeActionOperation>> ComputeOperationsAsync(CancellationToken cancellationToken)
  {
    var operations = new List<CodeActionOperation>();
    Solution changedSolution = await this.codeChangeOperation(cancellationToken);
    NavigationTarget navigationTarget = await this.navigationTargetCalculation(changedSolution, cancellationToken);

    operations.Add(new ApplyChangesOperation(changedSolution));

    if (navigationTarget != null)
    {
      operations.Add(new DocumentNavigationOperation(navigationTarget.DocumentId, navigationTarget.Position));
    }

    return operations;
  }
}

internal class NavigationTarget
{

  public NavigationTarget(DocumentId documentId, int position)
  {
    this.DocumentId = documentId;
    this.Position = position;
  }

  public DocumentId DocumentId { get; }

  public int Position { get; }

}

新的CodeAction可以在CodeFixProvider中使用,而不是CodeAction.Create()

public class MyCodeFixProvider : CodeFixProvider
{
  ...

  public async override Task RegisterCodeFixesAsync(CodeFixContext context)
  {
    await Task.Run(() =>
      {
        Diagnostics diagnostics = context.Diagnostics.First();
        CodeAction codeFix = new NavigateAfterCodeChangeAction(
          "Title",
          c => CreateXmlDocs(...)
          (s, c) => CalculateNavigationTarget(context.Document));

        context.RegisterCodeFix(codeFix, diagnostics);
      }
    ).ConfigureAwait(false);
  }

  private static NavigationTarget CalculateNavigationTarget(Document doc)
  {
    // Calculate the navigation target here...

    // Example: Navigate to position 42 of the document
    return new NavigationTarget(doc.Id, 42);
  }

  ...
}

【讨论】:

  • 我发现创建自定义 CodeAction 的技术有趣且有用。我发现我必须以与 Title 属性类似的方式覆盖属性 EquivalenceKey 以避免警告。
猜你喜欢
  • 2021-05-03
  • 1970-01-01
  • 1970-01-01
  • 2018-03-30
  • 2016-09-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多