【问题标题】:How to get Invoked method name in Roslyn?如何在 Roslyn 中获取调用的方法名称?
【发布时间】:2017-07-28 23:39:50
【问题描述】:

我有这样的代码;

class abc{
    void A()
    {
        //Some to do statements
    }
    void B()
    {
        var obj=A();
    }
    void C()
    {
        var call=B();
    }
}

我想使用 roslyn 查找 Invoked 方法名称。

像这里的 o/p 将是:

  • 对于方法 B:调用方法 A
  • 对于方法 C:调用的方法 A

我想要这样的东西:

root.DescendantNodes().OfType<InvocationExpressionSyntax>().Where(md => md.Identifier.ValueText.Equals(methodName)).FirstOrDefault();

但 InvocationExpression 不包含要访问的标识符。 如何获取标识符名称

【问题讨论】:

  • Class.Method()someDelegateField()new SomeClass()someDelegateArray[5]() 之类的调用呢?
  • 您发布的代码在很多方面都是错误的,这是否相关?例如,您调用 void 方法并将结果分配为一个值。
  • 我知道我的代码是错误的。我刚刚输入了一个示例来定义我的场景。实际上我想要调用表达式,它们是类中定义的方法,实际上由其他方法调用

标签: c# roslyn


【解决方案1】:

我同意 SLaks 的观点,如果您想要的是:

“我想要方法调用语法节点,其中接收者语法——让我强调一下语法——是等于某个特定字符串的单个标识符”

那么你想要的查询类似于

var root = tree.GetRoot();
var nodes = from node in root.DescendantNodes()
                         .OfType<InvocationExpressionSyntax>()
            let id = node.Expression as IdentifierNameSyntax
            where id != null
            where id.Identifier.ValueText == methodName
            select node;

但我认为这可能不是你想要的。如果您想要的是“我想确切地知道调用了哪个方法,无论它是写为A(...) 还是Foo.Bar.A(...),那么您根本不想考虑语法。你'将需要使用语义分析器来获取与调用关联的符号,然后检查该符号是否标识了您感兴趣的方法。

您主要对句法还是语义分析感兴趣? Roslyn 也可以,但您只是在查看您提供的代码中的语法。

如果您正在寻找的是语义分析,那么您想做这样的事情:

var tree = CSharpSyntaxTree.ParseText(code);
var c = CSharpCompilation.Create("asm.dll");
c = c.AddSyntaxTrees(tree);
var model = c.GetSemanticModel(tree);
string methodName = "A";

var root = tree.GetRoot();
var symbols = from node in root.DescendantNodes()
                           .OfType<InvocationExpressionSyntax>()
            let symbol = model.GetSymbolInfo(node.Expression).Symbol as IMethodSymbol
            where symbol != null
            where symbol.Name = methodName
            select symbol;

【讨论】:

  • where id?.Identifier.ValueText == methodName :)
  • 这里的“r”是什么?
【解决方案2】:

InvocationExpressionSyntax 没有 Identifier 的原因是因为在这种情况下可能有 var obj = this.A(),所以 InvocationExpressionSyntax 将包含 ExpressionSyntax 类型的属性 Expression(可能是 IdentifierNameSyntax 类型),

1.对于您的情况,简单的答案是您可以像这样访问属性表达式。

foreach (var item in root.DescendantNodes()
.OfType<InvocationExpressionSyntax>())
             {
                var expr = item.Expression;
                if (expr is IdentifierNameSyntax)
                {
                    IdentifierNameSyntax identifierName = r as IdentifierNameSyntax; // identifierName is your method name
                }

                if (expr is MemberAccessExpressionSyntax)
                {
                    MemberAccessExpressionSyntax memberAccessExpressionSyntax = r as MemberAccessExpressionSyntax;
                    //memberAccessExpressionSyntax.Name is your method name
                }
            }

2.但是对于精确查找,调用方法与您声明必须使用语义信息的方法相同,如 Roslyn 项目中的此示例
https://github.com/dotnet/roslyn/wiki/FAQ#how-do-i-find-all-calls-in-a-compilation-into-a-particular-namespace

【讨论】:

    【解决方案3】:

    您误解了这些节点在语法树中的作用。

    您应该使用 VS 中的 Roslyn Syntax Visualizer 来查看方法调用的节点实际上是什么样的。

    简而言之:InvocationExpression 仅表示 someExpression(some arguments)。该表达式可以是许多事物,例如构造函数调用、成员访问、数组访问或解析为方法或委托的任何其他表达式。
    您需要检查InvocationExpressionSyntaxKind 并弄清楚您希望如何处理每个可能的表达式。

    【讨论】:

    • 我相信调用表达式和对象创建表达式(构造函数调用)是不同的。
    猜你喜欢
    • 2013-07-07
    • 2011-07-03
    • 1970-01-01
    • 2014-07-11
    • 2011-10-27
    • 1970-01-01
    • 2013-12-17
    • 1970-01-01
    • 2012-03-27
    相关资源
    最近更新 更多