Skip to content

参数符号(IParameterSymbol)

📋 文档信息

难度: 🟢 简单
预计阅读时间: 15 分钟
前置知识: 语法树基础、符号系统
适合人群: 初级到中级开发者


📋 快速导航

章节难度阅读时间链接
概览🟢2 分钟查看
核心属性🟢3 分钟查看
参数类型详解🟡5 分钟查看
完整示例🟡2 分钟查看
真实使用场景🔴4 分钟查看
最佳实践🟡3 分钟查看
反模式和常见错误🟡2 分钟查看

🎯 概览

IParameterSymbol 表示 C# 中的参数,包括方法参数、索引器参数、委托参数和 lambda 参数。

本文档涵盖:

  • 参数符号的核心属性和方法
  • 不同类型的参数(普通参数、ref/out/in、params等)
  • 参数修饰符和默认值处理
  • 实际应用场景和最佳实践

典型应用场景:

  • 依赖注入分析
  • 参数验证代码生成
  • 方法签名分析
  • API 文档生成

核心属性

IParameterSymbol 提供了丰富的属性来描述 C# 参数的各个方面:

csharp
IParameterSymbol parameterSymbol;

// ============================================================
// 基本信息
// ============================================================

// 参数名称
string name = parameterSymbol.Name;

// 参数类型
ITypeSymbol type = parameterSymbol.Type;

// 参数位置(从 0 开始)
int ordinal = parameterSymbol.Ordinal;

// 是否是 this 参数(扩展方法的第一个参数)
bool isThis = parameterSymbol.IsThis;

// 是否是 params 参数
bool isParams = parameterSymbol.IsParams;

// ============================================================
// 参数修饰符
// ============================================================

// 参数的引用类型
RefKind refKind = parameterSymbol.RefKind;
// RefKind: None, Ref, Out, In, RefReadOnlyParameter

// 是否是 ref 参数
bool isRef = parameterSymbol.RefKind == RefKind.Ref;

// 是否是 out 参数
bool isOut = parameterSymbol.RefKind == RefKind.Out;

// 是否是 in 参数
bool isIn = parameterSymbol.RefKind == RefKind.In;

// 是否是 ref readonly 参数
bool isRefReadOnly = parameterSymbol.RefKind == RefKind.RefReadOnlyParameter;

// ============================================================
// 默认值
// ============================================================

// 是否有显式默认值
bool hasExplicitDefaultValue = parameterSymbol.HasExplicitDefaultValue;

// 显式默认值
object? explicitDefaultValue = parameterSymbol.ExplicitDefaultValue;

// 是否是可选参数
bool isOptional = parameterSymbol.IsOptional;

// ============================================================
// 可空性 (C# 8+)
// ============================================================

// 参数类型的可空注解
NullableAnnotation nullableAnnotation = parameterSymbol.Type.NullableAnnotation;

// 是否是可空引用类型
bool isNullableReferenceType = 
    nullableAnnotation == NullableAnnotation.Annotated;

// ============================================================
// 关联符号
// ============================================================

// 包含的方法
IMethodSymbol containingMethod = parameterSymbol.ContainingSymbol as IMethodSymbol;

// 包含的属性(对于索引器参数)
IPropertySymbol containingProperty = parameterSymbol.ContainingSymbol as IPropertySymbol;

// ============================================================
// 其他属性
// ============================================================

// 是否是 discard 参数 (C# 9+)
bool isDiscard = parameterSymbol.IsDiscard;

// 参数的作用域类型
ScopedKind scopedKind = parameterSymbol.ScopedKind;
// ScopedKind: None, ScopedValue, ScopedRef

参数类型详解

ref 参数

csharp
// ref 参数示例
public class RefParameterExample
{
    // ref 参数:传递引用,可以读写
    public void Swap(ref int a, ref int b)
    {
        int temp = a;
        a = b;
        b = temp;
    }
}

// 检测 ref 参数
public bool IsRefParameter(IParameterSymbol parameter)
{
    return parameter.RefKind == RefKind.Ref;
}

out 参数

csharp
// out 参数示例
public class OutParameterExample
{
    // out 参数:传递引用,必须在方法中赋值
    public bool TryParse(string input, out int result)
    {
        return int.TryParse(input, out result);
    }
    
    // 多个 out 参数
    public void GetDimensions(out int width, out int height)
    {
        width = 1920;
        height = 1080;
    }
}

// 检测 out 参数
public bool IsOutParameter(IParameterSymbol parameter)
{
    return parameter.RefKind == RefKind.Out;
}

in 参数

csharp
// in 参数示例(C# 7.2+)
public class InParameterExample
{
    // in 参数:传递只读引用,避免大型结构体的复制
    public double CalculateDistance(in Point3D point1, in Point3D point2)
    {
        double dx = point2.X - point1.X;
        double dy = point2.Y - point1.Y;
        double dz = point2.Z - point1.Z;
        return Math.Sqrt(dx * dx + dy * dy + dz * dz);
    }
}

public struct Point3D
{
    public double X { get; set; }
    public double Y { get; set; }
    public double Z { get; set; }
}

// 检测 in 参数
public bool IsInParameter(IParameterSymbol parameter)
{
    return parameter.RefKind == RefKind.In;
}

params 参数

csharp
// params 参数示例
public class ParamsParameterExample
{
    // params 参数:可变数量的参数
    public int Sum(params int[] numbers)
    {
        return numbers.Sum();
    }
    
    // params 可以与其他参数组合
    public string Format(string template, params object[] args)
    {
        return string.Format(template, args);
    }
}

// 检测 params 参数
public bool IsParamsParameter(IParameterSymbol parameter)
{
    return parameter.IsParams;
}

this 参数(扩展方法)

csharp
// this 参数示例(扩展方法)
public static class StringExtensions
{
    // this 参数:扩展方法的第一个参数
    public static bool IsNullOrEmpty(this string value)
    {
        return string.IsNullOrEmpty(value);
    }
    
    // 泛型扩展方法
    public static T FirstOrDefault<T>(this IEnumerable<T> source, T defaultValue)
    {
        return source.FirstOrDefault() ?? defaultValue;
    }
}

// 检测 this 参数(扩展方法)
public bool IsExtensionMethodParameter(IParameterSymbol parameter)
{
    return parameter.IsThis;
}

RefKind 枚举详解

csharp
/// <summary>
/// RefKind 枚举的完整说明
/// </summary>
public class RefKindExplainer
{
    public string ExplainRefKind(RefKind refKind)
    {
        return refKind switch
        {
            RefKind.None => 
                "普通参数:按值传递(值类型复制值,引用类型复制引用)",
            
            RefKind.Ref => 
                "ref 参数:传递引用,可以读写,调用时必须传递已初始化的变量",
            
            RefKind.Out => 
                "out 参数:传递引用,必须在方法中赋值,调用时可以传递未初始化的变量",
            
            RefKind.In => 
                "in 参数:传递只读引用,不能修改,用于避免大型结构体的复制开销",
            
            RefKind.RefReadOnlyParameter => 
                "ref readonly 参数:传递只读引用(较少使用)",
            
            _ => "未知的 RefKind"
        };
    }
    
    /// <summary>
    /// 分析参数的传递方式
    /// </summary>
    public void AnalyzeParameterPassing(IParameterSymbol parameter)
    {
        Console.WriteLine($"参数: {parameter.Name}");
        Console.WriteLine($"类型: {parameter.Type.ToDisplayString()}");
        Console.WriteLine($"传递方式: {ExplainRefKind(parameter.RefKind)}");
        
        // 特殊标记
        if (parameter.IsThis)
            Console.WriteLine("  这是扩展方法的 this 参数");
        
        if (parameter.IsParams)
            Console.WriteLine("  这是 params 参数");
        
        if (parameter.IsOptional)
            Console.WriteLine("  这是可选参数");
    }
}

默认值和可选参数

csharp
/// <summary>
/// 处理参数的默认值
/// </summary>
public class ParameterDefaultValueHandler
{
    /// <summary>
    /// 提取参数的默认值
    /// </summary>
    public string GetDefaultValueString(IParameterSymbol parameter)
    {
        if (!parameter.HasExplicitDefaultValue)
            return "无默认值";
        
        var defaultValue = parameter.ExplicitDefaultValue;
        
        if (defaultValue == null)
            return "null";
        
        var type = parameter.Type;
        
        if (type.SpecialType == SpecialType.System_String)
            return $"\"{defaultValue}\"";
        
        if (type.SpecialType == SpecialType.System_Char)
            return $"'{defaultValue}'";
        
        if (type.SpecialType == SpecialType.System_Boolean)
            return defaultValue.ToString()!.ToLower();
        
        return defaultValue.ToString()!;
    }
    
    /// <summary>
    /// 分析方法的可选参数
    /// </summary>
    public void AnalyzeOptionalParameters(IMethodSymbol method)
    {
        Console.WriteLine($"方法: {method.Name}");
        
        var requiredParams = new List<IParameterSymbol>();
        var optionalParams = new List<IParameterSymbol>();
        
        foreach (var param in method.Parameters)
        {
            if (param.IsOptional || param.HasExplicitDefaultValue)
            {
                optionalParams.Add(param);
            }
            else
            {
                requiredParams.Add(param);
            }
        }
        
        Console.WriteLine($"必需参数: {requiredParams.Count}");
        foreach (var param in requiredParams)
        {
            Console.WriteLine($"  {param.Type.ToDisplayString()} {param.Name}");
        }
        
        Console.WriteLine($"可选参数: {optionalParams.Count}");
        foreach (var param in optionalParams)
        {
            var defaultValue = GetDefaultValueString(param);
            Console.WriteLine($"  {param.Type.ToDisplayString()} {param.Name} = {defaultValue}");
        }
    }
}

// 可选参数示例
public class OptionalParameterExample
{
    // 带默认值的可选参数
    public void Log(string message, string level = "INFO", bool timestamp = true)
    {
        if (timestamp)
        {
            Console.WriteLine($"[{DateTime.Now}] [{level}] {message}");
        }
        else
        {
            Console.WriteLine($"[{level}] {message}");
        }
    }
    
    // 混合必需和可选参数
    public void Connect(string host, int port = 80, int timeout = 30)
    {
        // 连接逻辑
    }
}

完整示例:参数分析器

csharp
/// <summary>
/// 完整的参数分析器,展示如何全面分析参数符号
/// </summary>
public class ComprehensiveParameterAnalyzer
{
    public ParameterAnalysisResult AnalyzeParameter(IParameterSymbol parameter)
    {
        var result = new ParameterAnalysisResult
        {
            Name = parameter.Name,
            Type = parameter.Type.ToDisplayString(),
            Ordinal = parameter.Ordinal,
            
            // 参数修饰符
            RefKind = parameter.RefKind.ToString(),
            IsThis = parameter.IsThis,
            IsParams = parameter.IsParams,
            IsOptional = parameter.IsOptional,
            IsDiscard = parameter.IsDiscard,
            
            // 默认值
            HasExplicitDefaultValue = parameter.HasExplicitDefaultValue
        };
        
        // 提取默认值
        if (parameter.HasExplicitDefaultValue)
        {
            result.DefaultValue = parameter.ExplicitDefaultValue?.ToString();
        }
        
        // 分析可空性
        result.NullableAnnotation = 
            parameter.Type.NullableAnnotation.ToString();
        
        // 分析包含符号
        if (parameter.ContainingSymbol is IMethodSymbol method)
        {
            result.ContainingMethod = method.Name;
            result.IsExtensionMethod = method.IsExtensionMethod;
        }
        else if (parameter.ContainingSymbol is IPropertySymbol property)
        {
            result.ContainingProperty = property.Name;
            result.IsIndexerParameter = property.IsIndexer;
        }
        
        // 分类参数
        result.ParameterCategory = CategorizeParameter(parameter);
        
        return result;
    }
    
    private string CategorizeParameter(IParameterSymbol parameter)
    {
        if (parameter.IsThis)
            return "扩展方法 this 参数";
        
        if (parameter.IsParams)
            return "params 可变参数";
        
        if (parameter.RefKind == RefKind.Out)
            return "out 输出参数";
        
        if (parameter.RefKind == RefKind.Ref)
            return "ref 引用参数";
        
        if (parameter.RefKind == RefKind.In)
            return "in 只读引用参数";
        
        if (parameter.IsOptional || parameter.HasExplicitDefaultValue)
            return "可选参数";
        
        return "普通参数";
    }
}

public class ParameterAnalysisResult
{
    public string Name { get; set; }
    public string Type { get; set; }
    public int Ordinal { get; set; }
    
    // 参数修饰符
    public string RefKind { get; set; }
    public bool IsThis { get; set; }
    public bool IsParams { get; set; }
    public bool IsOptional { get; set; }
    public bool IsDiscard { get; set; }
    
    // 默认值
    public bool HasExplicitDefaultValue { get; set; }
    public string? DefaultValue { get; set; }
    
    // 可空性
    public string NullableAnnotation { get; set; }
    
    // 包含符号
    public string? ContainingMethod { get; set; }
    public string? ContainingProperty { get; set; }
    public bool IsExtensionMethod { get; set; }
    public bool IsIndexerParameter { get; set; }
    
    // 分类
    public string ParameterCategory { get; set; }
}

真实使用场景

场景 1:生成方法调用代码

csharp
/// <summary>
/// 为方法生成调用代码
/// </summary>
public class MethodCallGenerator
{
    public string GenerateMethodCall(IMethodSymbol method, string instanceName = "obj")
    {
        var sb = new StringBuilder();
        
        // 生成方法调用
        if (method.IsStatic)
        {
            sb.Append($"{method.ContainingType.Name}.{method.Name}(");
        }
        else
        {
            sb.Append($"{instanceName}.{method.Name}(");
        }
        
        // 生成参数列表
        var paramStrings = new List<string>();
        
        foreach (var param in method.Parameters)
        {
            var paramStr = GenerateParameterUsage(param);
            paramStrings.Add(paramStr);
        }
        
        sb.Append(string.Join(", ", paramStrings));
        sb.Append(")");
        
        return sb.ToString();
    }
    
    private string GenerateParameterUsage(IParameterSymbol parameter)
    {
        var sb = new StringBuilder();
        
        // 添加修饰符
        if (parameter.RefKind == RefKind.Ref)
            sb.Append("ref ");
        else if (parameter.RefKind == RefKind.Out)
            sb.Append("out ");
        else if (parameter.RefKind == RefKind.In)
            sb.Append("in ");
        
        // 添加参数名或默认值
        if (parameter.HasExplicitDefaultValue)
        {
            // 可选参数可以省略
            sb.Append($"/* {parameter.Name} */");
        }
        else
        {
            sb.Append(parameter.Name);
        }
        
        return sb.ToString();
    }
}

场景 2:验证参数的可空性

csharp
/// <summary>
/// 验证方法参数的可空性配置
/// </summary>
public class ParameterNullabilityValidator
{
    public List<string> ValidateNullability(IMethodSymbol method)
    {
        var issues = new List<string>();
        
        foreach (var param in method.Parameters)
        {
            // 检查引用类型参数的可空性
            if (param.Type.IsReferenceType)
            {
                var nullableAnnotation = param.Type.NullableAnnotation;
                
                // out 参数应该是非空的
                if (param.RefKind == RefKind.Out &&
                    nullableAnnotation == NullableAnnotation.Annotated)
                {
                    issues.Add(
                        $"out 参数 {param.Name} 不应该是可空类型 " +
                        $"({param.Type.ToDisplayString()})");
                }
                
                // 可选参数如果默认值是 null,应该标记为可空
                if (param.HasExplicitDefaultValue &&
                    param.ExplicitDefaultValue == null &&
                    nullableAnnotation == NullableAnnotation.NotAnnotated)
                {
                    issues.Add(
                        $"参数 {param.Name} 的默认值是 null," +
                        $"应该标记为可空类型");
                }
                
                // 非可空参数不应该有 null 默认值
                if (param.HasExplicitDefaultValue &&
                    param.ExplicitDefaultValue == null &&
                    nullableAnnotation == NullableAnnotation.NotAnnotated)
                {
                    issues.Add(
                        $"非可空参数 {param.Name} 不应该有 null 默认值");
                }
            }
        }
        
        return issues;
    }
}

场景 3:分析参数传递模式

csharp
/// <summary>
/// 分析方法的参数传递模式
/// </summary>
public class ParameterPatternAnalyzer
{
    public ParameterPatternReport AnalyzePatterns(IMethodSymbol method)
    {
        var report = new ParameterPatternReport
        {
            MethodName = method.Name
        };
        
        foreach (var param in method.Parameters)
        {
            // 分析不同的参数模式
            
            // 1. 输入参数(普通参数)
            if (param.RefKind == RefKind.None && !param.IsParams)
            {
                report.InputParameters.Add(param.Name);
            }
            
            // 2. 输出参数(out 参数)
            if (param.RefKind == RefKind.Out)
            {
                report.OutputParameters.Add(param.Name);
            }
            
            // 3. 输入输出参数(ref 参数)
            if (param.RefKind == RefKind.Ref)
            {
                report.InputOutputParameters.Add(param.Name);
            }
            
            // 4. 只读引用参数(in 参数)
            if (param.RefKind == RefKind.In)
            {
                report.ReadOnlyRefParameters.Add(param.Name);
            }
            
            // 5. 可变参数(params)
            if (param.IsParams)
            {
                report.VariableParameters.Add(param.Name);
            }
            
            // 6. 可选参数
            if (param.IsOptional || param.HasExplicitDefaultValue)
            {
                report.OptionalParameters.Add(param.Name);
            }
            
            // 7. 扩展方法参数
            if (param.IsThis)
            {
                report.ExtensionMethodParameter = param.Name;
            }
        }
        
        return report;
    }
}

public class ParameterPatternReport
{
    public string MethodName { get; set; }
    public List<string> InputParameters { get; set; } = new();
    public List<string> OutputParameters { get; set; } = new();
    public List<string> InputOutputParameters { get; set; } = new();
    public List<string> ReadOnlyRefParameters { get; set; } = new();
    public List<string> VariableParameters { get; set; } = new();
    public List<string> OptionalParameters { get; set; } = new();
    public string? ExtensionMethodParameter { get; set; }
}

💡 最佳实践

  1. 使用 RefKind 枚举判断参数类型

    csharp
    // ✅ 正确:使用 RefKind 枚举
    switch (parameter.RefKind)
    {
        case RefKind.None:
            // 普通参数
            break;
        case RefKind.Ref:
            // ref 参数
            break;
        case RefKind.Out:
            // out 参数
            break;
        case RefKind.In:
            // in 参数
            break;
    }
    
    // ❌ 不推荐:使用字符串比较
    if (parameter.ToString().Contains("ref"))
    {
        // 不可靠
    }
  2. 检查默认值是否存在

    csharp
    // ✅ 正确:检查 HasExplicitDefaultValue
    if (parameter.HasExplicitDefaultValue)
    {
        var defaultValue = parameter.ExplicitDefaultValue;
    }
    
    // ❌ 错误:直接访问 ExplicitDefaultValue
    var defaultValue = parameter.ExplicitDefaultValue; // 可能无意义
  3. 区分可选参数和有默认值的参数

    csharp
    // ✅ 正确:两者可能不同
    bool isOptional = parameter.IsOptional;
    bool hasDefault = parameter.HasExplicitDefaultValue;
    
    // 某些情况下,参数可以是可选的但没有显式默认值
    // 例如:COM 互操作中的可选参数
  4. 识别扩展方法

    csharp
    // ✅ 正确:检查第一个参数的 IsThis 属性
    if (method.IsExtensionMethod && 
        method.Parameters.Length > 0 &&
        method.Parameters[0].IsThis)
    {
        var extendedType = method.Parameters[0].Type;
        Console.WriteLine($"扩展类型: {extendedType.ToDisplayString()}");
    }
  5. 处理 params 参数

    csharp
    // ✅ 正确:检查 IsParams 属性
    if (parameter.IsParams)
    {
        // params 参数必须是数组类型
        if (parameter.Type is IArrayTypeSymbol arrayType)
        {
            var elementType = arrayType.ElementType;
            Console.WriteLine($"params 元素类型: {elementType.ToDisplayString()}");
        }
    }
  6. 按位置访问参数

    csharp
    // ✅ 正确:使用 Ordinal 属性
    var firstParam = method.Parameters.FirstOrDefault(p => p.Ordinal == 0);
    
    // 或者直接使用索引
    if (method.Parameters.Length > 0)
    {
        var firstParam = method.Parameters[0];
    }
  7. 处理参数的可空性

    csharp
    // ✅ 正确:检查参数类型的可空注解
    var nullableAnnotation = parameter.Type.NullableAnnotation;
    
    if (parameter.Type.IsReferenceType &&
        nullableAnnotation == NullableAnnotation.Annotated)
    {
        // 这是可空引用类型参数(如 string?)
    }
  8. 验证 out 参数

    csharp
    // ✅ 正确:out 参数应该是非空的
    if (parameter.RefKind == RefKind.Out)
    {
        if (parameter.Type.IsReferenceType &&
            parameter.Type.NullableAnnotation == NullableAnnotation.Annotated)
        {
            // 警告:out 参数通常不应该是可空的
        }
    }
  9. 分析参数顺序

    csharp
    // ✅ 正确:参数顺序很重要
    // 必需参数 -> 可选参数 -> params 参数
    var requiredParams = method.Parameters
        .Where(p => !p.IsOptional && !p.HasExplicitDefaultValue && !p.IsParams)
        .OrderBy(p => p.Ordinal);
    
    var optionalParams = method.Parameters
        .Where(p => p.IsOptional || p.HasExplicitDefaultValue)
        .OrderBy(p => p.Ordinal);
    
    var paramsParam = method.Parameters
        .FirstOrDefault(p => p.IsParams);
  10. 处理 discard 参数

    csharp
    // ✅ 正确:检查 discard 参数(C# 9+)
    if (parameter.IsDiscard)
    {
        // 这是 discard 参数(如 _ )
        // 通常用于忽略不需要的参数
    }

⚠️ 反模式和常见错误

反模式 1:混淆 ref、out 和 in 参数

csharp
// ❌ 错误:将所有引用参数当作相同处理
public void BadExample(IParameterSymbol parameter)
{
    if (parameter.RefKind != RefKind.None)
    {
        // 错误:ref、out、in 有不同的语义
        Console.WriteLine("这是引用参数");
    }
}

// ✅ 正确:区分不同的引用参数类型
public void GoodExample(IParameterSymbol parameter)
{
    switch (parameter.RefKind)
    {
        case RefKind.Ref:
            Console.WriteLine("ref 参数:可读可写");
            break;
        case RefKind.Out:
            Console.WriteLine("out 参数:必须在方法中赋值");
            break;
        case RefKind.In:
            Console.WriteLine("in 参数:只读引用");
            break;
    }
}

反模式 2:忽略参数的默认值

csharp
// ❌ 错误:假设所有可选参数都有默认值
public void BadExample(IParameterSymbol parameter)
{
    if (parameter.IsOptional)
    {
        // 可能没有显式默认值
        var defaultValue = parameter.ExplicitDefaultValue;
    }
}

// ✅ 正确:检查是否有显式默认值
public void GoodExample(IParameterSymbol parameter)
{
    if (parameter.IsOptional)
    {
        if (parameter.HasExplicitDefaultValue)
        {
            var defaultValue = parameter.ExplicitDefaultValue;
            Console.WriteLine($"默认值: {defaultValue}");
        }
        else
        {
            Console.WriteLine("可选参数但没有显式默认值");
        }
    }
}

反模式 3:不检查 params 参数的类型

csharp
// ❌ 错误:假设 params 参数总是特定类型
public void BadExample(IParameterSymbol parameter)
{
    if (parameter.IsParams)
    {
        // 错误:params 可以是任何数组类型
        Console.WriteLine("params int[] 参数");
    }
}

// ✅ 正确:检查 params 参数的实际类型
public void GoodExample(IParameterSymbol parameter)
{
    if (parameter.IsParams)
    {
        if (parameter.Type is IArrayTypeSymbol arrayType)
        {
            var elementType = arrayType.ElementType;
            Console.WriteLine($"params {elementType.ToDisplayString()}[] 参数");
        }
    }
}

反模式 4:忽略扩展方法的 this 参数

csharp
// ❌ 错误:将 this 参数当作普通参数
public void BadExample(IMethodSymbol method)
{
    if (method.IsExtensionMethod)
    {
        // 错误:没有特殊处理第一个参数
        foreach (var param in method.Parameters)
        {
            Console.WriteLine($"参数: {param.Name}");
        }
    }
}

// ✅ 正确:特殊处理 this 参数
public void GoodExample(IMethodSymbol method)
{
    if (method.IsExtensionMethod && method.Parameters.Length > 0)
    {
        var thisParam = method.Parameters[0];
        Console.WriteLine($"扩展类型: {thisParam.Type.ToDisplayString()}");
        
        // 处理其他参数
        foreach (var param in method.Parameters.Skip(1))
        {
            Console.WriteLine($"参数: {param.Name}");
        }
    }
}

反模式 5:不考虑参数顺序

csharp
// ❌ 错误:忽略参数的顺序
public void BadExample(IMethodSymbol method)
{
    var parameters = method.Parameters.OrderBy(p => p.Name); // 错误!
    
    foreach (var param in parameters)
    {
        Console.WriteLine(param.Name);
    }
}

// ✅ 正确:保持参数的原始顺序
public void GoodExample(IMethodSymbol method)
{
    // 参数已经按 Ordinal 排序
    foreach (var param in method.Parameters)
    {
        Console.WriteLine($"[{param.Ordinal}] {param.Name}");
    }
    
    // 或者显式按 Ordinal 排序
    var sortedParams = method.Parameters.OrderBy(p => p.Ordinal);
}

🔗 相关文档

本文档集

相关主题


📚 下一步

学习完参数符号后,建议继续学习:

  1. 方法符号 - 方法符号参考

    • 理解方法与参数的关系
    • 学习方法签名分析
  2. 实际应用 - 常见场景

    • 依赖注入分析
    • 参数验证

最后更新: 2026-02-05
文档版本: 1.0

基于 MIT 许可发布