13

我可以使用以下代码从对特定方法的所有调用的解决方案中获取列表:

var createCommandList = new List<MethodSymbol>();
INamedTypeSymbol interfaceSymbol = 
   (from p
    in solution.Projects
    select p.GetCompilation().GetTypeByMetadataName(
        "BuySeasons.BsiServices.DataResource.IBsiDataConnection")
    ).FirstOrDefault();
foreach (ISymbol symbol in interfaceSymbol.GetMembers("CreateCommand"))
{
    if (symbol.Kind == CommonSymbolKind.Method
        && symbol is MethodSymbol)
    {
        createCommandList.Add(symbol as MethodSymbol);
    }
}
foreach (MethodSymbol methodSymbol in createCommandList)
{
    foreach (ReferencedSymbol referenceSymbol
        in methodSymbol.FindReferences(solution))
    {
        foreach (ReferenceLocation referenceLocation
            in from l
               in referenceSymbol.Locations
               orderby l.Document.FilePath
               select l)
        {
            if (referenceLocation.Location.GetLineSpan(false)
                    .StartLinePosition.Line ==
                referenceLocation.Location.GetLineSpan(false)
                    .EndLinePosition.Line)
            {
                Debug.WriteLine("{0} {1} at {2} {3}/{4} - {5}",
                    methodSymbol.Name,
                    "(" + String.Join(",",
                       (from p
                        in methodSymbol.Parameters
                        select p.Type.Name + " " + p.Name).ToArray()
                       ) + ")",
                Path.GetFileName(referenceLocation.Location.GetLineSpan(false)
                    .Path),
                referenceLocation.Location.GetLineSpan(false)
                    .StartLinePosition.Line,
                referenceLocation.Location.GetLineSpan(false)
                    .StartLinePosition.Character,
                referenceLocation.Location.GetLineSpan(false)
                    .EndLinePosition.Character));
            }
            else
            {
                throw new ApplicationException("Call spans multiple lines");
            }
        }
    }
}

但这给了我一个ReferencedSymbol. 虽然这给了我调用该方法的文件和行号,但我还想获得调用该方法的特定参数。我怎样才能转换我拥有的东西或获得与 Roslyn 相同的信息?(请注意,我首先使用该方法加载解决方案,Solution.Load然后循环查找该方法的定义/声明位置(createCommandList))。

4

3 回答 3

2

您已经在这里使用 Roslyn。当您拥有 时referenceSymbol,您可以获取方法声明语法,然后向下查看树以获取参数列表。

我插入了一个arguments使用您的变量referenceSymbol

// Snip start
foreach (MethodSymbol methodSymbol in createCommandList)
{
    foreach (ReferencedSymbol referenceSymbol
        in methodSymbol.FindReferences(solution))
    {
        var arguments = referenceSymbol.Definition.DeclaringSyntaxNodes.First()
            .DescendantNodes().OfType<ParameterSyntax>().ToList();

        foreach (ReferenceLocation referenceLocation in
            from l
            in referenceSymbol.Locations
            orderby l.Document.FilePath
            select l)
        {
// Snip end

当您执行调试输出时,您可以使用该参数列表来获取名称。

我的解决方案需要获取 的First()DeclaringSyntaxNodes我不太喜欢,但找不到另一种方法来获取语法树的后代节点。

于 2014-01-30T17:59:37.980 回答
1

我发现了另一种从可能对其他人也有效的方法中获取参数列表的方法。

假设我有以下具有两个参数的方法:

public string DebugPage(string enabled, string show){
  //do stuff 
}

然后,您可以随心所欲地获得节点。例如,这给了我一个公共方法列表:

IEnumerable<MethodDeclarationSyntax> methods = from m in root.DescendantNodes().OfType<MethodDeclarationSyntax>() where m.Modifiers.ToString().Contains("public") select m;

然后我可以遍历该方法列表以获取该方法的ParameterList属性,该属性被公开以使此操作非常容易。在此循环结束时,列表parameters将保存方法中每个参数的名称(在Debug上面的方法示例中,它将保存值enabled并且show如预期的那样):

var parameters = new List<string>();

foreach (var method in methods)
{
   foreach (var n in method.ParameterList.Parameters)
   {
     var parameterName = n.Identifier.Text;
     parameters.Add(parameterName);
   }
}
于 2017-10-24T03:53:46.720 回答
0

您可以在它出现的特定源位置搜索引用的语法树以找到您要查找的节点。您需要从树的根节点使用 DescendentNodes 之类的调用,并且您可能需要请求您正在寻找的语言特定节点类型。在引用树中拥有节点后,您就可以使用该树的语义模型来告诉您有关参数的其他信息。

于 2012-06-29T19:43:17.870 回答