【问题标题】:GetClassificationSpans in Visual Studio 2015 doesn't return anythingVisual Studio 2015 中的 GetClassificationSpan 不返回任何内容
【发布时间】:2015-11-07 21:02:58
【问题描述】:

我有一个标记器(ITagger 的子类),我正在尝试调用 GetClassificationSpans,以便我可以使用分类来查找 cmets 以使用标记进行格式化。这在 Visual Studio 2013 中有效,但现在在 Visual Studio 2015 中运行时,GetClassificationSpan 总是返回一个空列表 - 即使我在调试器中检查了跨度并且它肯定传递了一个带有注释的跨度。

有人知道 2015 年调用 GetClassificationSpans 会发生什么变化吗?

顺便说一句:我通过在我的标记器提供程序(ITaggerProvider 的子类)中导入 IClassifierAggregatorService 并将其传递给标记器的构造函数来获取分类器:

[import]
IClassifierAggregatorService aggregator;

然后我在我从提供者那里得到的聚合器上的标记器中使用以下调用:

IList<ClassificationSpan> lstClassifiers = aggregator.GetClassifier(span.Snapshot.TextBuffer).GetClassificationSpans(span);

而且,正如我所说,lstClassifiers 列表始终为空。在 VS2013 中运行 find 完全相同的代码。我似乎在网上找不到任何提及 VS2015 中可能导致此问题的任何更改。

谢谢,

【问题讨论】:

    标签: visual-studio-2015 visual-studio-extensions vspackage visual-studio-sdk


    【解决方案1】:

    我遇到了同样的问题,但在不同的环境中。从我的谷歌搜索来看,他们似乎已经更改了分类器,以便它们被延迟初始化......我猜GetClassificationSpans() 不会强制初始化它们。 MSFT 仍然认为这是一个错误,因此您可能需要对问题进行投票on VS Connect

    一个潜在的解决方法(如 MSFT 所建议的)是改用 TagAggregator 而不是 IClassifier。所以而不是:

    var service = container.GetService<IClassifierAggregatorService>();
    var classifier = service.GetClassifier(textView.TextBuffer);
    var spans = classifier.GetClassificationSpans(new SnapshotSpan(...));
    

    您可以改为这样写:

    var service = container.GetService<IViewTagAggregatorFactoryService>();
    var aggregator = service.CreateTagAggregator<IClassificationTag>(textView);
    var tags = aggregator.GetTags(new SnapshotSpan(...)));
    

    这将返回IMappingTagSpan&lt;IClassificationTag&gt; 的列表而不是ClassificationSpan 的列表,因此您使用它们的方式略有不同。但是基础数据似乎大部分是相同的——即,您可以获得每个词法元素的分类和跨度。有一些细微的差别(参见 VS Connect 上的描述),但结果对于我的应用程序来说已经足够了。

    【讨论】:

      【解决方案2】:

      嗯。在尝试了不同的东西之后,它看起来像是几个问题:

      1. 执行顺序必须已更改,因此在我之前调用 GetClassificationSpans 的位置之前似乎没有设置分类。 (在缓冲区级别标记器的构造函数中[而不是在视图级别标记器中]。)我现在仅在处理 BufferChanged/LayoutChanged 期间调用 GetCLassificationSpans。 (我现在唯一的问题是打开文件时我似乎没有收到 BufferChanged 事件。希望解决这个问题不会太难。)
      2. 如果我使用传递给提供程序的缓冲区引用,在那里设置对 IClassifier 的引用并将其传递给我的标记器而不是聚合器,它似乎工作得更好(因此我停止在快照跨度)。
      3. 通过从之前使用的 v12 引用更新对 SDK DLL 的 v14 的引用,我得到了更好的结果。

      希望对遇到相同问题的人有所帮助。

      【讨论】:

      • 在 SDK DLL 版本之间移动应该不会真正产生影响 - 一旦您实际在 Visual Studio 中运行,您仍然会调用相同的代码。
      【解决方案3】:

      因此,一般而言,ITagger API 不要求标记器返回“真实”信息。相反,它是一个返回“您当时拥有的任何信息”的 API。如果给您带来麻烦的缓冲区是 C# 或 VB 缓冲区,那是因为在 VS2015 中,我们将 Roslyn 中的所有内容都移动为异步的,因此在我们重新计算数据之前,对 GetClassificationSpans/GetTags 的调用可能不会返回任何内容。有一个新的 API,IAccurateTagger,用于请求标记器提供“真实”数据,尽管这不是您希望在文本缓冲区更改中运行的东西,因为您会降低性能。

      如果您尝试在 VS2015 中查找 cmets,而让您感到困惑的文件是 C# 或 VB 缓冲区,则最好调用 Roslyn API,它为您提供所需的直接语法树数据。如果它是不同类型的缓冲区,您至少最好调用 IAccurateTagger,但由于性能影响,请尽可能小心地执行此操作。

      (此外,如果您尝试构建一个在您键入时自动格式化的扩展,使用分类标记器会给您带来其他麻烦。VS2013 中存在错误,您必须解决 C# 会过时的问题如果您在标签更改期间调用它。)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2015-10-10
        • 1970-01-01
        • 2015-11-13
        • 2020-04-27
        • 2019-04-06
        • 2012-02-15
        • 2020-09-07
        相关资源
        最近更新 更多