【问题标题】:Roslyn Analyzer - Finding the current concrete implementation of interface's method callRoslyn Analyzer - 查找接口方法调用的当前具体实现
【发布时间】:2018-09-20 02:17:33
【问题描述】:

我正在尝试编写一个 Roslyn 分析器来检测来自接口的特定实现的方法调用,但我在检测实现类型时遇到了问题。

当我使用类型化变量作为具体实现时,它正确识别方法,但当我使用类型化变量作为接口时,它不能正确识别方法。主要是想弄清楚如何使用 Roslyn 代码分析 API 获取接口的底层实现的类型

这是要分析的示例代码。它正确检测到第二个Operate 方法调用但不是第一个,即使两者都使用Operable 中的具体实现

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            IOperable ioperable = new Operable();
            ioperable.Operate();

            Operable operable = new Operable();
            operable.Operate();
        }
    }

    public interface IOperable
    {
        void Operate();
    }

    public class Operable : IOperable
    {
        public void Operate()
        {

        }
    }
}

这是我目前的来源:

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

private static void AnalyzeInvocation(SyntaxNodeAnalysisContext context)
{
    var invocation = (InvocationExpressionSyntax)context.Node;

    var memberAccess = invocation.Expression as MemberAccessExpressionSyntax;
    if (memberAccess == null || !memberAccess.IsKind(SyntaxKind.SimpleMemberAccessExpression))
    {
        return;
    }

    var ident = memberAccess.Name.Identifier;
    if (ident.ToString().ToLower() != "operate")
    {
        return;
    }

    var calledFromType = context.SemanticModel.GetTypeInfo(memberAccess.Expression).Type;
    if (calledFromType.MetadataName != "Operable")
    {
        return;
    }
    context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation()));
}

【问题讨论】:

    标签: c# roslyn abstract-syntax-tree analyzer roslyn-code-analysis


    【解决方案1】:

    我会让你失望,但 Roslyn 是一个静态分析器,默认情况下它不可能检索类型、调用等的动态信息。

    为了实现这一点,您需要在 roslyn 下实现自定义动态分析,该分析将调查对变量的所有赋值、参数传递等,以确定它可以拥有的有关对象(类型、方法等)的所有信息代码中的当前时间。

    在下面的例子中要清楚:

    public interface IOperable
    {
        void Operate();
    }
    
    public class Operable : IOperable
    {
       ...
    }
    
    public class OperableOther : IOperable
    {
       ...
    }
    
    ...
    
    IOperable ioperable = new Operable();
    ioperable.Operate(); // at this time will invoke Operable.Operate();
    
    ioperable = new OperableOther();
    ioperable.Operate(); // at this time will OperableOther.Operate();
    

    Roslyn 可以检索关于变量 ioperable 的编译时间信息,它是一个 IOperable,但不能给出它将来自第一个分配的 Operable 和来自第二个分配的 OperableOther。但是,如果您将所有变量修改等累积起来,您可以自己完成。

    【讨论】:

    • 非常感谢您澄清并提供潜在的解决方法!
    猜你喜欢
    • 1970-01-01
    • 2013-03-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    相关资源
    最近更新 更多