c# - 实现缺失接口(interface)的 Roslyn 2.x CodeFix,委托(delegate)给成员,VS 2017

标签 c# visual-studio-2017 roslyn roslyn-code-analysis

背景

我正在寻求创建一个 Roslyn CodeFix,它将响应来自 Visual Studio 附带的内置分析器的诊断警告,它将识别未实现或部分实现的接口(interface),从而允许我遍历丢失的接口(interface)成员,并生成自定义代码,将方法调用委托(delegate)给实现该接口(interface)的类型的成员字段。

(Visual Studio 附带的 Roslyn Analyzers 和 CodeFixes 确实提供了此功能,但我需要自定义和扩展代码的生成,这是不可能的,因为 Microsoft 实现都标记为 internal.)

请注意:接口(interface)几乎总是位于外部的第三方程序集中,我无权访问它的源代码。

例如开始于:

public class CustomDocumentDBClient : IDocumentClient
{
}

期望的结果将类似于以下内容(在实践中,一旦基本原则起作用,我将创建多个版本来添加额外的代码来包装方法调用):

public class CustomDocumentDBClient : IDocumentClient
{
    // Field to which calls are delegated, initialised by the constructor
    private readonly IDocumentClient _documentClientImplementation;

    // Constructor
    public CustomDocumentDBClient (IDocumentClient documentClientImplementation)
    {
        _documentClientImplementation = documentClientImplementation;
    }

    // Interface method that delegates to private field for invocation 
    public Task<ResourceResponse<Attachment>> CreateAttachmentAsync(string documentLink, object attachment, RequestOptions options = null)
    {
        return _documentClientImplementation.CreateAttachmentAsync(documentLink, attachment, options);
    }

    // Interface method that delegates to private field for invocation    
    public Task<ResourceResponse<Attachment>> CreateAttachmentAsync(string documentLink, Stream mediaStream, MediaOptions options = null, RequestOptions requestOptions = null)
    {
        return _documentClientImplementation.CreateAttachmentAsync(documentLink, mediaStream, options, requestOptions);
    }
    ...
    other methods
    ...
}

我尝试了什么

我花了一些时间阅读有关 Roslyn 的语法树和语义模型功能的教程。

我还检查了来自 GitHub 的 Roslyn 源代码——它确实包含了我希望实现的确切功能;然而,代码在各种复杂的类中交织在一起,并作为 internal 方法实现,不能被覆盖或扩展,甚至不能提取到独立项目中。

来自调查多个样本,以及一个相关的 SO 问题 How to see if a class has implemented the interface with Roslyn我得出的结论是,我必须使用 Roslyn 语义模型来获取有关接口(interface)及其声明成员的信息。

一旦我可以获得接口(interface)成员,我就可以使用 SyntaxFactory 构建所需的输出代码,并且我使用“Roslyn Quoter”作为指导。

从默认模板创建一个 CodeFix,响应正确的诊断代码很简单,而且它正在运行。

问题

我遇到的问题是采用诊断位置标识的 token ,它似乎是一个 SimpleBaseTypeSyntax token ,并且

  1. 验证它实际上代表一个接口(interface),
  2. 获取允许我枚举第三方接口(interface)成员的符号定义。

Syntax Visualizer 指示接口(interface)声明节点的类型为 SimpleBaseType

因此,我使用以下代码从语法树中获取 token 作为 SimpleBaseTypeSyntax-

    // Find the interface Syntax Token detected by the diagnostic.
    var interfaceBaseTypeSyntax =
        root.FindToken(diagnosticSpan.Start).Parent.AncestorsAndSelf()
            .OfType<SimpleBaseTypeSyntax>().First();

a) 这确实会返回一个标记,其中包含语法树中相关节点的信息 - 但是,我看不到任何“InterfaceTypeSyntax”类型或 IsInterface 方法来验证它实际上是一个接口(interface)。

b) 我相信我应该能够使用 semanticModel.GetSymbolInfo(interfaceBaseTypeSyntax),但是这总是返回 null - 请记住接口(interface)是在外部程序集中声明的。

我需要做些什么才能通过 GetSymbolInfo 提供该信息,还是我应该采取另一种方法...?

非常感谢您的建议...

最佳答案

发了这么快就找到了,有点尴尬,不过解决办法好像是引用了Identifier这是 SimpleBaseTypeSyntax 的后代.

var interfaceSymbolInfo =
semanticModel.GetSymbolInfo(interfaceBaseTypeSyntax.DescendantNodes().First());

然后,通过调用:

var interfaceTypeInfo = 
semanticModel.GetTypeInfo(interfaceBaseTypeSyntax.DescendantNodes().First());

然后我可以使用 interfaceTypeInfo.Type.IsInterface验证我确实找到了接口(interface)类型,并且还访问了 interfaceTypeInfo.Type.GetMembers() .

通过语法可视化工具,答案就在眼前。

Syntax Visualizer

我暂时将此打开,以防其他人有更好的解决方案...谢谢!

关于c# - 实现缺失接口(interface)的 Roslyn 2.x CodeFix,委托(delegate)给成员,VS 2017,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44091647/

相关文章:

c# - Visual Studio 2019 导致调试缓慢和内存使用率高

c# - Visual Studio mscorlib 类源代码

c# - 我可以在 Visual Studio 解决方案中列出所有*不可用*项目吗?

visual-studio - Visual Studio创建多个/其他工作区

c# - 使用 SyntaxNode.ReplaceNode 替换同一棵树中的多个节点

c# - 我如何在 C# 中获取调用方法

c# - 对象必须实现 iconvertible devexpress

c# - 越来越奇怪 BadImageFormatException : Cannot load a reference assembly for execution

c# - 在什么情况下 Text 可能与 ValueText 不同

c# - 如何使用 Roslyn CSharpCompilation 避免内存泄漏