You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何映射InvocationExpressionSyntax实参至形参?Roslyn方法问询

Great question! Mapping invocation arguments to method parameters in Roslyn—especially when dealing with optional parameters, named arguments, or params arrays—requires accounting for all the nuanced logic the C# compiler uses. Let's cover both manual mapping (if you need custom logic) and the built-in Roslyn API that matches the compiler's behavior exactly.

Manual Argument-to-Parameter Mapping (For Custom Scenarios)

If you need to implement custom matching logic, follow these steps to map InvocationExpressionSyntax arguments to a method's parameters:

  1. Get the method's semantic symbol
    First, bind the syntax node to its semantic model to get the IMethodSymbol (which contains the method's parameter metadata):

    var semanticModel = // Retrieve from your compilation context (e.g., AnalysisContext)
    var invocationExpr = // Your target InvocationExpressionSyntax instance
    var methodSymbol = semanticModel.GetSymbolInfo(invocationExpr).Symbol as IMethodSymbol;
    
    if (methodSymbol == null) return; // Handle cases where the symbol couldn't be resolved
    
  2. Separate named and positional arguments
    Split the invocation's arguments into named (those with a NameColon) and positional (those without) groups:

    var arguments = invocationExpr.ArgumentList.Arguments;
    var namedArgs = arguments
        .Where(arg => arg.NameColon != null)
        .ToDictionary(
            arg => arg.NameColon.Name.Identifier.Text,
            arg => arg
        );
    var positionalArgs = arguments.Where(arg => arg.NameColon == null).ToList();
    
  3. Map parameters to arguments
    First match named arguments directly by parameter name, then fill remaining parameters with positional arguments in order. For optional parameters without an explicit argument, mark them as using the default value:

    var parameterMap = new Dictionary<IParameterSymbol, ArgumentSyntax?>();
    int positionalIndex = 0;
    
    foreach (var param in methodSymbol.Parameters)
    {
        // Check for a matching named argument first
        if (namedArgs.TryGetValue(param.Name, out var namedArg))
        {
            parameterMap[param] = namedArg;
            namedArgs.Remove(param.Name); // Avoid duplicate matches
        }
        // Fall back to positional arguments if available
        else if (positionalIndex < positionalArgs.Count)
        {
            parameterMap[param] = positionalArgs[positionalIndex];
            positionalIndex++;
        }
        // No explicit argument—use the optional parameter's default value
        else
        {
            parameterMap[param] = null;
        }
    }
    

    Now parameterMap contains each parameter paired with its corresponding argument (or null if the optional parameter's default value is used).

Roslyn provides an API that replicates the C# compiler's exact argument-binding logic, so you don't have to handle edge cases like reordered named arguments, params array expansion, or optional parameter defaults manually.

Use SemanticModel.GetInvocationExpressionInfo() to get a structured breakdown of the argument-parameter mappings:

var semanticModel = // Retrieve from your compilation context
var invocationExpr = // Your target InvocationExpressionSyntax instance

var invocationInfo = semanticModel.GetInvocationExpressionInfo(invocationExpr);
if (invocationInfo.Symbol == null) return;

foreach (var argInfo in invocationInfo.Arguments)
{
    var parameter = argInfo.Parameter;
    var argumentSyntax = argInfo.Argument;

    if (argumentSyntax != null)
    {
        Console.WriteLine($"Parameter '{parameter.Name}' matched with explicit argument: {argumentSyntax}");
    }
    else
    {
        Console.WriteLine($"Parameter '{parameter.Name}' uses its default value: {parameter.DefaultValue}");
    }
}

Each ArgumentInfo in invocationInfo.Arguments includes:

  • Parameter: The IParameterSymbol the argument is bound to
  • Argument: The ArgumentSyntax for the explicit argument (or null if using an optional parameter's default)
  • IsParamsArray: Whether the argument is part of a params array expansion
  • IsOptional: Whether the argument is using an optional parameter's default value

Key Notes

  • Always use SemanticModel instead of relying solely on syntax nodes—semantic analysis gives you access to the actual method signature and parameter metadata, which is critical for accurate mapping.
  • The built-in GetInvocationExpressionInfo method handles all edge cases the C# compiler does, so it's the recommended approach unless you need custom matching logic.

内容的提问来源于stack exchange,提问作者user3284063

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 07:02:03