C# 使用Roslyn获取方法参数

C# 使用Roslyn获取方法参数,c#,.net,roslyn,C#,.net,Roslyn,我可以使用以下代码从对特定方法的所有调用的解决方案中获取列表: var createCommandList = new List<MethodSymbol>(); INamedTypeSymbol interfaceSymbol = (from p in solution.Projects select p.GetCompilation().GetTypeByMetadataName( "BuySeasons.BsiServices.DataR

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

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");
            }
        }
    }
}
var createCommandList=new List();
INAMEDYPESYMBOL接口符号=
(来自p
在解决方案中。项目
选择p.GetCompilation().GetTypeByMetadataName(
“BuySeasons.BsiServices.DataResource.IBMIDataConnection”)
).FirstOrDefault();
foreach(interfaceSymbol.GetMembers(“CreateCommand”)中的ISymbol符号)
{
if(symbol.Kind==CommonSymbolKind.Method
&&符号是方法(符号)
{
createCommandList.Add(符号作为MethodSymbol);
}
}
foreach(createCommandList中的MethodSymbol MethodSymbol)
{
foreach(参考符号参考符号
在methodSymbol.FindReferences中(解决方案))
{
foreach(ReferenceLocation ReferenceLocation
从l
在参考符号位置中
orderby l.Document.FilePath
选择l)
{
if(referenceLocation.Location.GetLineSpan)(false)
.令人吃惊的位置==
referenceLocation.Location.GetLineSpan(false)
.EndLinePosition.Line)
{
Debug.WriteLine({0}{1}位于{2}{3}/{4}-{5}),
methodSymbol.Name,
(“+String.Join(“,”,
(来自p
在methodSymbol.Parameters中
选择p.Type.Name+“”+p.Name).ToArray()
) + ")",
Path.GetFileName(referenceLocation.Location.GetLineSpan(false)
.Path),
referenceLocation.Location.GetLineSpan(false)
.位置.线路,
referenceLocation.Location.GetLineSpan(false)
.令人吃惊的位置,
referenceLocation.Location.GetLineSpan(false)
.EndLinePosition.Character));
}
其他的
{
抛出新的ApplicationException(“调用跨越多行”);
}
}
}
}

但这给了我一个
ReferencedSymbol
列表。虽然这给了我调用该方法的文件和行号,但我也希望得到调用该方法的特定参数。我如何转换我所拥有的信息,或与Roslyn获得相同的信息?(请注意,我首先使用
solution.load
方法加载解决方案,然后循环查找该方法的定义/声明位置(
createCommandList
)。

您可以在引用出现的特定源位置搜索该引用的语法树,以找到您要查找的节点。您需要使用类似于树的根节点的子节点的调用,并且可能需要请求您正在查找的特定于语言的节点类型。一旦你在referecing树中有了节点,你就可以使用该树的语义模型来告诉你关于参数的其他信息。

你已经在这里使用了Roslyn。当您有一个
引用SYMBOL
时,您可以获得方法声明语法,然后向下查看树以获得参数列表

我插入了一个
参数
变量,该变量使用您的
引用符号

// 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
//剪断启动
foreach(createCommandList中的MethodSymbol MethodSymbol)
{
foreach(参考符号参考符号
在methodSymbol.FindReferences中(解决方案))
{
var arguments=referenceSymbol.Definition.DeclaringSyntaxNodes.First()
.degenantNodes().OfType().ToList();
foreach(ReferenceLocation ReferenceLocation in
从l
在参考符号位置中
orderby l.Document.FilePath
选择l)
{
//剪断端
执行调试输出时,可以使用该参数列表获取名称


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

我发现了另一种从方法获取参数列表的方法,这种方法可能也适用于其他方法

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

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;
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);
   }
}