C# params 关键字详解:从入门到精通(保姆级教程)

C# params 关键字详解:从入门到精通(保姆级教程)

📚 目录

  1. [什么是 params 关键字?](#什么是 params 关键字?)
  2. [params 的基本语法](#params 的基本语法)
  3. [params 的使用场景](#params 的使用场景)
  4. [params 的底层原理](#params 的底层原理)
  5. [params 的最佳实践](#params 的最佳实践)
  6. 常见陷阱和注意事项
  7. 实战案例
  8. 面试常见问题

1. 什么是 params 关键字?

1.1 官方定义

params 是 C# 中的一个关键字,允许方法接受可变数量的参数 。使用 params 关键字,你可以向方法传递逗号分隔的参数列表或指定类型的数组。

1.2 通俗理解

想象你去餐厅点餐:

  • 普通方法:必须按菜单固定数量点菜(比如只能点3个菜)
  • params 方法:可以点任意数量的菜(1个、2个、10个都可以)
csharp 复制代码
// 普通方法:参数数量固定
void OrderFood(string dish1, string dish2) { }  // 只能点2个菜

// params 方法:参数数量可变
void OrderFood(params string[] dishes) { }  // 可以点任意数量的菜

2. params 的基本语法

2.1 最简单的例子

csharp 复制代码
public class ParamsDemo
{
    // 定义一个使用 params 的方法
    public static int Sum(params int[] numbers)
    {
        int total = 0;
        foreach (int num in numbers)
        {
            total += num;
        }
        return total;
    }
    
    public static void Main()
    {
        // 方式1:传递多个参数
        Console.WriteLine(Sum(1, 2, 3));           // 输出:6
        Console.WriteLine(Sum(1, 2, 3, 4, 5));      // 输出:15
        
        // 方式2:传递数组
        int[] arr = { 1, 2, 3, 4, 5, 6 };
        Console.WriteLine(Sum(arr));                 // 输出:21
        
        // 方式3:不传参数
        Console.WriteLine(Sum());                    // 输出:0
    }
}

2.2 语法规则

csharp 复制代码
// 规则1:params 只能用于一维数组
public void Method1(params int[] numbers) { }           // ✅ 正确
public void Method2(params int[,] numbers) { }          // ❌ 错误:不能是二维数组
public void Method3(params int[][] numbers) { }         // ❌ 错误:不能是交错数组

// 规则2:一个方法只能有一个 params 参数
public void Method4(params int[] nums, params string[] strs) { }  // ❌ 错误

// 规则3:params 必须是最后一个参数
public void Method5(string name, params int[] scores) { }  // ✅ 正确
public void Method6(params int[] scores, string name) { }  // ❌ 错误

// 规则4:params 不能和 ref、out 一起使用
public void Method7(ref params int[] nums) { }  // ❌ 错误
public void Method8(out params int[] nums) { }  // ❌ 错误

3. params 的使用场景

3.1 场景1:字符串拼接

csharp 复制代码
public class StringHelper
{
    // 传统方式
    public static string Concat(string[] strings)
    {
        return string.Join("", strings);
    }
    
    // params 方式(更优雅)
    public static string ConcatWithParams(params string[] strings)
    {
        return string.Join("", strings);
    }
}

// 使用对比
class Program
{
    static void Main()
    {
        // 传统方式:需要先创建数组
        string[] words = new string[] { "Hello", " ", "World" };
        Console.WriteLine(StringHelper.Concat(words));
        
        // params 方式:直接传参
        Console.WriteLine(StringHelper.ConcatWithParams("Hello", " ", "World"));
        Console.WriteLine(StringHelper.ConcatWithParams("C#", " ", "Params", " ", "Demo"));
    }
}

3.2 场景2:日志记录

csharp 复制代码
public class Logger
{
    public static void Log(string level, string message, params object[] args)
    {
        string timestamp = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
        string formattedMessage = string.Format(message, args);
        Console.WriteLine($"[{timestamp}] [{level}] {formattedMessage}");
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        Logger.Log("INFO", "用户 {0} 登录成功", "张三");
        Logger.Log("WARNING", "重试次数: {0}, 等待时间: {1}ms", 3, 5000);
        Logger.Log("ERROR", "数据库连接失败: {0}, 错误码: {1}, 详情: {2}", 
                   "Timeout", 10086, "Connection timeout after 30s");
    }
}

// 输出:
// [2024-01-01 10:30:25] [INFO] 用户 张三 登录成功
// [2024-01-01 10:30:25] [WARNING] 重试次数: 3, 等待时间: 5000ms
// [2024-01-01 10:30:25] [ERROR] 数据库连接失败: Timeout, 错误码: 10086, 详情: Connection timeout after 30s

3.3 场景3:数学计算

csharp 复制代码
public class MathUtils
{
    // 求最大值
    public static T Max<T>(params T[] numbers) where T : IComparable<T>
    {
        if (numbers == null || numbers.Length == 0)
            throw new ArgumentException("至少需要一个参数");
        
        T max = numbers[0];
        for (int i = 1; i < numbers.Length; i++)
        {
            if (numbers[i].CompareTo(max) > 0)
                max = numbers[i];
        }
        return max;
    }
    
    // 求平均值
    public static double Average(params int[] numbers)
    {
        if (numbers.Length == 0) return 0;
        return numbers.Average();
    }
    
    // 计算方差
    public static double Variance(params double[] numbers)
    {
        if (numbers.Length < 2) return 0;
        
        double avg = numbers.Average();
        double sum = 0;
        
        foreach (double num in numbers)
        {
            sum += Math.Pow(num - avg, 2);
        }
        
        return sum / (numbers.Length - 1);
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        Console.WriteLine($"最大值: {MathUtils.Max(3, 7, 2, 9, 1, 5)}");           // 9
        Console.WriteLine($"最大值: {MathUtils.Max(3.14, 2.78, 1.41, 1.73)}");    // 3.14
        Console.WriteLine($"平均值: {MathUtils.Average(60, 70, 80, 90, 100)}");    // 80
        Console.WriteLine($"方差: {MathUtils.Variance(2, 4, 4, 4, 5, 5, 7, 9)}");  // 4.57...
    }
}

3.4 场景4:UI 控件初始化

csharp 复制代码
public class UIBuilder
{
    // 创建按钮组
    public static List<Button> CreateButtons(params string[] buttonTexts)
    {
        var buttons = new List<Button>();
        
        for (int i = 0; i < buttonTexts.Length; i++)
        {
            buttons.Add(new Button
            {
                Text = buttonTexts[i],
                Tag = i,
                Width = 100,
                Height = 30
            });
        }
        
        return buttons;
    }
    
    // 添加多个控件到容器
    public static void AddControls(Control parent, params Control[] controls)
    {
        foreach (var control in controls)
        {
            parent.Controls.Add(control);
        }
    }
}

// 在 WinForms 或 WPF 中使用
class Program
{
    static void Main()
    {
        // 创建多个按钮
        var buttons = UIBuilder.CreateButtons("确定", "取消", "保存", "删除", "刷新");
        
        // 添加到容器
        var panel = new Panel();
        UIBuilder.AddControls(panel, buttons.ToArray());
    }
}

4. params 的底层原理

4.1 编译后的代码

csharp 复制代码
// 你写的代码
public void PrintNumbers(params int[] numbers)
{
    foreach (var num in numbers)
    {
        Console.WriteLine(num);
    }
}

// 调用代码
PrintNumbers(1, 2, 3, 4, 5);

// 编译器实际生成的代码(IL层面)
// 编译器会自动将参数包装成数组
PrintNumbers(new int[] { 1, 2, 3, 4, 5 });

4.2 IL 代码查看

csharp 复制代码
// 使用 ILSpy 或 dnSpy 查看编译后的代码
.method public hidebysig instance void 
    PrintNumbers(int32[] 'numbers') cil managed
{
    .param [1]
    .custom instance void System.ParamArrayAttribute::.ctor()
}

4.3 性能分析

csharp 复制代码
public class ParamsPerformance
{
    // 方法1:使用 params
    public static void WithParams(params int[] numbers)
    {
        // 方法体
    }
    
    // 方法2:直接传数组
    public static void WithArray(int[] numbers)
    {
        // 方法体
    }
    
    public static void TestPerformance()
    {
        // 场景1:传递少量参数(3-5个)
        // params 会创建新数组,有微小性能开销
        WithParams(1, 2, 3);  // 内部会 new int[3]
        
        // 场景2:传递大量参数
        int[] largeArray = Enumerable.Range(1, 10000).ToArray();
        WithArray(largeArray);    // ✅ 推荐:直接使用已有数组
        WithParams(largeArray);   // ⚠️ 注意:这里不会创建新数组,直接使用原数组
    }
}

5. params 的最佳实践

5.1 与可选参数结合

csharp 复制代码
public class QueryBuilder
{
    // 结合可选参数和 params
    public static string BuildQuery(
        string tableName, 
        params string[] fields)
    {
        string fieldList = fields.Length > 0 
            ? string.Join(", ", fields) 
            : "*";
        
        return $"SELECT {fieldList} FROM {tableName}";
    }
    
    // 重载版本
    public static string BuildQuery(
        string tableName, 
        string condition = "", 
        params string[] fields)
    {
        string fieldList = fields.Length > 0 
            ? string.Join(", ", fields) 
            : "*";
        
        string whereClause = string.IsNullOrEmpty(condition) 
            ? "" 
            : $" WHERE {condition}";
        
        return $"SELECT {fieldList} FROM {tableName}{whereClause}";
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        Console.WriteLine(QueryBuilder.BuildQuery("Users"));
        // 输出:SELECT * FROM Users
        
        Console.WriteLine(QueryBuilder.BuildQuery("Users", "Id", "Name", "Email"));
        // 输出:SELECT Id, Name, Email FROM Users
        
        Console.WriteLine(QueryBuilder.BuildQuery("Users", "Age > 18", "Name", "Age"));
        // 输出:SELECT Name, Age FROM Users WHERE Age > 18
    }
}

5.2 空值处理

csharp 复制代码
public class SafeParams
{
    // 安全的 params 方法
    public static void SafeLog(string format, params object[] args)
    {
        // 检查 args 是否为 null
        if (args == null)
        {
            Console.WriteLine(format);
            return;
        }
        
        try
        {
            Console.WriteLine(format, args);
        }
        catch (FormatException)
        {
            Console.WriteLine("日志格式错误: " + format);
        }
    }
    
    // 防御性编程
    public static int SafeSum(params int[] numbers)
    {
        // 处理 null 情况
        if (numbers == null) return 0;
        
        int sum = 0;
        for (int i = 0; i < numbers.Length; i++)
        {
            sum += numbers[i];
        }
        return sum;
    }
}

// 测试
class Program
{
    static void Main()
    {
        // 测试 null 参数
        SafeParams.SafeLog("测试", null);  // ✅ 安全处理
        
        // 测试空数组
        Console.WriteLine(SafeParams.SafeSum());           // 0
        Console.WriteLine(SafeParams.SafeSum(null));       // 0
        Console.WriteLine(SafeParams.SafeSum(1, 2, 3));    // 6
    }
}

5.3 泛型结合

csharp 复制代码
public class ParamsGeneric
{
    // 泛型 params 方法
    public static T[] CreateArray<T>(params T[] items)
    {
        T[] result = new T[items.Length];
        Array.Copy(items, result, items.Length);
        return result;
    }
    
    // 创建列表
    public static List<T> CreateList<T>(params T[] items)
    {
        return new List<T>(items);
    }
    
    // 合并多个数组
    public static T[] ConcatArrays<T>(params T[][] arrays)
    {
        int totalLength = arrays.Sum(arr => arr.Length);
        T[] result = new T[totalLength];
        
        int index = 0;
        foreach (var arr in arrays)
        {
            arr.CopyTo(result, index);
            index += arr.Length;
        }
        
        return result;
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        // 创建数组
        int[] numbers = ParamsGeneric.CreateArray(1, 2, 3, 4, 5);
        
        // 创建列表
        List<string> names = ParamsGeneric.CreateList("张三", "李四", "王五");
        
        // 合并数组
        int[] arr1 = { 1, 2, 3 };
        int[] arr2 = { 4, 5, 6 };
        int[] arr3 = { 7, 8, 9 };
        
        int[] merged = ParamsGeneric.ConcatArrays(arr1, arr2, arr3);
        Console.WriteLine(string.Join(", ", merged));  // 1, 2, 3, 4, 5, 6, 7, 8, 9
    }
}

6. 常见陷阱和注意事项

6.1 陷阱1:方法重载的歧义

csharp 复制代码
public class OverloadTrap
{
    public static void Test(int x)
    {
        Console.WriteLine("单个参数: " + x);
    }
    
    public static void Test(params int[] x)
    {
        Console.WriteLine("params 参数: " + string.Join(", ", x));
    }
    
    public static void Main()
    {
        Test(10);        // 调用的是哪个? 输出:单个参数: 10
        Test(10, 20);    // 调用的是哪个? 输出:params 参数: 10, 20
        Test();          // 调用的是哪个? 输出:params 参数: 
    }
    // 编译器优先选择非 params 版本
}

6.2 陷阱2:参数匹配优先级

csharp 复制代码
public class PriorityTrap
{
    public static void Process(int x, int y)
    {
        Console.WriteLine("精确匹配");
    }
    
    public static void Process(params int[] numbers)
    {
        Console.WriteLine("params 匹配");
    }
    
    public static void Main()
    {
        Process(1, 2);  // 输出:精确匹配(编译器优先选择精确匹配)
    }
}

6.3 陷阱3:params 和 null

csharp 复制代码
public class NullTrap
{
    public static void PrintNumbers(params int[] numbers)
    {
        if (numbers == null)
        {
            Console.WriteLine("参数是 null");
            return;
        }
        
        Console.WriteLine($"数组长度: {numbers.Length}");
    }
    
    public static void Main()
    {
        PrintNumbers(null);      // 输出:参数是 null
        PrintNumbers();          // 输出:数组长度: 0
        PrintNumbers(1, 2, 3);   // 输出:数组长度: 3
    }
    // 注意:不传参数和传 null 是不同的!
}

6.4 陷阱4:性能开销

csharp 复制代码
public class PerformanceTrap
{
    public static void ProcessArray(int[] numbers)
    {
        // 直接使用数组
    }
    
    public static void ProcessParams(params int[] numbers)
    {
        // 使用 params
    }
    
    public static void Main()
    {
        int[] largeArray = Enumerable.Range(1, 1000000).ToArray();
        
        // 好的做法:直接传数组
        ProcessArray(largeArray);  // ✅ 不创建新数组
        
        // 不好的做法:传递大量参数
        ProcessParams(1, 2, 3, 4, 5);  // ✅ 少量参数没问题
        
        // 注意:下面这行会直接使用数组,不会创建新数组
        ProcessParams(largeArray);  // ✅ 也不会创建新数组
    }
}

7. 实战案例

7.1 案例1:灵活的配置构建器

csharp 复制代码
public class ConfigurationBuilder
{
    private Dictionary<string, object> _settings = new Dictionary<string, object>();
    
    // 使用 params 添加多个配置项
    public ConfigurationBuilder AddSettings(params (string key, object value)[] settings)
    {
        foreach (var setting in settings)
        {
            _settings[setting.key] = setting.value;
        }
        return this;
    }
    
    // 添加带条件的配置
    public ConfigurationBuilder AddConditionalSettings(
        bool condition, 
        params (string key, object value)[] settings)
    {
        if (condition)
        {
            foreach (var setting in settings)
            {
                _settings[setting.key] = setting.value;
            }
        }
        return this;
    }
    
    // 批量添加
    public ConfigurationBuilder AddFromEnvironment(params string[] envVars)
    {
        foreach (var envVar in envVars)
        {
            var value = Environment.GetEnvironmentVariable(envVar);
            if (value != null)
            {
                _settings[envVar] = value;
            }
        }
        return this;
    }
    
    public void Build()
    {
        foreach (var kv in _settings)
        {
            Console.WriteLine($"{kv.Key} = {kv.Value}");
        }
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        var config = new ConfigurationBuilder()
            .AddSettings(
                ("Server", "localhost"),
                ("Port", 5432),
                ("Database", "MyDB"),
                ("Username", "admin")
            )
            .AddConditionalSettings(
                Environment.Is64BitProcess,
                ("Use64Bit", true),
                ("MaxMemory", "16GB")
            )
            .AddFromEnvironment("PATH", "TEMP", "USERNAME");
        
        config.Build();
    }
}

7.2 案例2:验证器框架

csharp 复制代码
public class Validator
{
    private List<string> _errors = new List<string>();
    
    // 验证多个条件
    public Validator Validate(bool condition, string errorMessage)
    {
        if (!condition)
        {
            _errors.Add(errorMessage);
        }
        return this;
    }
    
    // 批量验证
    public Validator ValidateAll(params (bool condition, string message)[] validations)
    {
        foreach (var v in validations)
        {
            if (!v.condition)
            {
                _errors.Add(v.message);
            }
        }
        return this;
    }
    
    // 验证对象属性
    public Validator ValidateObject<T>(T obj, params Func<T, (bool, string)>[] rules)
    {
        foreach (var rule in rules)
        {
            var (isValid, message) = rule(obj);
            if (!isValid)
            {
                _errors.Add(message);
            }
        }
        return this;
    }
    
    public bool IsValid => !_errors.Any();
    public IReadOnlyList<string> Errors => _errors;
}

// 使用示例
class User
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string Email { get; set; }
}

class Program
{
    static void Main()
    {
        var user = new User
        {
            Name = "John",
            Age = 15,
            Email = "invalid-email"
        };
        
        var validator = new Validator();
        
        // 方式1:逐个验证
        validator.Validate(!string.IsNullOrEmpty(user.Name), "用户名不能为空")
                 .Validate(user.Age >= 18, "年龄必须大于18岁")
                 .Validate(user.Email.Contains("@"), "邮箱格式不正确");
        
        // 方式2:批量验证
        validator.ValidateAll(
            (!string.IsNullOrEmpty(user.Name), "用户名不能为空"),
            (user.Age >= 18, "年龄必须大于18岁"),
            (user.Email.Contains("@"), "邮箱格式不正确")
        );
        
        // 方式3:规则验证
        validator.ValidateObject(user,
            u => (!string.IsNullOrEmpty(u.Name), "用户名不能为空"),
            u => (u.Age >= 18, "年龄必须大于18岁"),
            u => (u.Email.Contains("@"), "邮箱格式不正确")
        );
        
        if (!validator.IsValid)
        {
            Console.WriteLine("验证失败:");
            foreach (var error in validator.Errors)
            {
                Console.WriteLine($"  - {error}");
            }
        }
    }
}

7.3 案例3:SQL 查询构建器

csharp 复制代码
public class SqlQueryBuilder
{
    private string _table;
    private List<string> _selectFields = new List<string>();
    private List<string> _whereConditions = new List<string>();
    private List<string> _orderByFields = new List<string>();
    
    public SqlQueryBuilder From(string table)
    {
        _table = table;
        return this;
    }
    
    public SqlQueryBuilder Select(params string[] fields)
    {
        _selectFields.AddRange(fields);
        return this;
    }
    
    public SqlQueryBuilder Where(params string[] conditions)
    {
        _whereConditions.AddRange(conditions);
        return this;
    }
    
    public SqlQueryBuilder OrderBy(params string[] fields)
    {
        _orderByFields.AddRange(fields);
        return this;
    }
    
    public SqlQueryBuilder WhereIf(bool condition, params string[] conditions)
    {
        if (condition)
        {
            _whereConditions.AddRange(conditions);
        }
        return this;
    }
    
    public string Build()
    {
        var sb = new StringBuilder();
        
        // SELECT 部分
        sb.Append("SELECT ");
        if (_selectFields.Any())
        {
            sb.Append(string.Join(", ", _selectFields));
        }
        else
        {
            sb.Append("*");
        }
        
        // FROM 部分
        sb.Append($" FROM {_table}");
        
        // WHERE 部分
        if (_whereConditions.Any())
        {
            sb.Append(" WHERE ");
            sb.Append(string.Join(" AND ", _whereConditions));
        }
        
        // ORDER BY 部分
        if (_orderByFields.Any())
        {
            sb.Append(" ORDER BY ");
            sb.Append(string.Join(", ", _orderByFields));
        }
        
        return sb.ToString();
    }
}

// 使用示例
class Program
{
    static void Main()
    {
        string searchName = "John";
        int minAge = 18;
        
        var query = new SqlQueryBuilder()
            .From("Users")
            .Select("Id", "Name", "Email", "Age")
            .Where("IsActive = 1")
            .WhereIf(!string.IsNullOrEmpty(searchName), $"Name LIKE '%{searchName}%'")
            .WhereIf(minAge > 0, $"Age >= {minAge}")
            .OrderBy("Name", "Age DESC");
        
        Console.WriteLine(query.Build());
        // 输出:SELECT Id, Name, Email, Age FROM Users WHERE IsActive = 1 AND Name LIKE '%John%' AND Age >= 18 ORDER BY Name, Age DESC
    }
}

8. 面试常见问题

Q1: params 和数组参数有什么区别?

csharp 复制代码
// 答案:
public class InterviewQuestion1
{
    // 数组参数
    public static void Method1(int[] numbers)
    {
        // 调用时必须传数组
    }
    
    // params 参数
    public static void Method2(params int[] numbers)
    {
        // 调用时可以直接传多个int
    }
    
    public static void Main()
    {
        // 数组参数
        Method1(new int[] { 1, 2, 3 });  // ✅ 必须这样调用
        // Method1(1, 2, 3);              // ❌ 错误
        
        // params 参数
        Method2(1, 2, 3);                 // ✅ 可以直接传
        Method2(new int[] { 1, 2, 3 });   // ✅ 也可以传数组
        Method2();                         // ✅ 可以不传
    }
}

Q2: params 参数可以是任意类型吗?

csharp 复制代码
// 答案:可以是任意类型,但必须是一维数组
public class InterviewQuestion2
{
    // 值类型
    public static void IntParams(params int[] numbers) { }
    
    // 引用类型
    public static void StringParams(params string[] strings) { }
    
    // 自定义类型
    public static void CustomParams(params MyClass[] objects) { }
    
    // 泛型
    public static void GenericParams<T>(params T[] items) { }
    
    // 混合类型(使用 object)
    public static void MixedParams(params object[] items) { }
}

// 使用示例
class Program
{
    static void Main()
    {
        MixedParams(1, "hello", 3.14, true, new object());
    }
}

Q3: params 的性能如何?什么时候应该避免使用?

csharp 复制代码
// 答案:
public class InterviewQuestion3
{
    // ✅ 适合使用 params 的场景
    public static void LogMessage(string format, params object[] args)
    {
        // 少量参数,不频繁调用
        Console.WriteLine(format, args);
    }
    
    // ❌ 不适合使用 params 的场景
    public static void ProcessLargeData(params int[] data)
    {
        // 如果 data 很大且频繁调用,每次都会创建新数组
        // 应该直接传数组
    }
    
    // ✅ 正确的做法
    public static void ProcessLargeDataCorrect(int[] data)
    {
        // 直接使用传入的数组,不创建副本
    }
}

Q4: params 可以和 out/ref 一起使用吗?

csharp 复制代码
// 答案:不可以
public class InterviewQuestion4
{
    // ❌ 编译错误
    // public static void Test(ref params int[] numbers) { }
    // public static void Test(out params int[] numbers) { }
    
    // ✅ 正确做法
    public static void Test(ref int[] numbers) { }
    public static void Test(out int[] numbers) 
    { 
        numbers = new int[0];
    }
}

Q5: params 如何处理空参数和 null?

csharp 复制代码
// 答案:
public class InterviewQuestion5
{
    public static void Test(params int[] numbers)
    {
        Console.WriteLine($"参数: {(numbers == null ? "null" : $"数组长度 {numbers.Length}")}");
    }
    
    public static void Main()
    {
        Test();              // 输出:参数: 数组长度 0
        Test(null);          // 输出:参数: null
        Test(1, 2, 3);       // 输出:参数: 数组长度 3
    }
}

📝 总结

什么时候使用 params?

  • ✅ 方法的参数数量不确定时
  • ✅ 希望提供简洁的调用语法时
  • ✅ 参数数量较少(通常少于10个)时
  • ✅ 构建流畅的 API 时

什么时候避免使用 params?

  • ❌ 性能敏感且频繁调用的方法
  • ❌ 参数数量很大时
  • ❌ 已经有现成的数组需要传递时

最佳实践清单

  1. 📌 params 必须是最后一个参数
  2. 📌 一个方法只能有一个 params 参数
  3. 📌 考虑处理 null 的情况
  4. 📌 提供非 params 的重载版本以提高性能
  5. 📌 参数数量不确定但类型相同时使用

🎯 练习题

练习1:实现一个灵活的字符串格式化器

csharp 复制代码
// 要求:实现一个 StringFormatter 类,可以格式化任意数量的参数
public class StringFormatter
{
    // 你的代码
    
    public static string Format(string template, params object[] args)
    {
        // 实现功能
        return string.Format(template, args);
    }
    
    // 扩展:支持命名参数
    public static string FormatNamed(string template, params (string name, object value)[] args)
    {
        // 实现功能
        string result = template;
        foreach (var arg in args)
        {
            result = result.Replace($"{{{arg.name}}}", arg.value?.ToString());
        }
        return result;
    }
}

练习2:实现迷你版的 LINQ

csharp 复制代码
// 要求:实现一些简单的 LINQ 方法,支持 params 参数
public class MiniLinq
{
    public static T[] Where<T>(params T[] items)
    {
        // 实现过滤逻辑
        return items;
    }
    
    public static TResult[] Select<T, TResult>(Func<T, TResult> selector, params T[] items)
    {
        // 实现映射逻辑
        return items.Select(selector).ToArray();
    }
    
    public static T FirstOrDefault<T>(params T[] items)
    {
        // 实现获取第一个元素
        return items.FirstOrDefault();
    }
}

希望这篇教程对你有帮助!如果还有任何问题,欢迎继续提问!🎉

相关推荐
請你喝杯Java2 小时前
Python 后端开发:从虚拟环境、pip、requirements.txt 到项目启动
开发语言·python·pip
也曾看到过繁星2 小时前
初识c++
开发语言·c++
2401_874732532 小时前
泛型编程与STL设计思想
开发语言·c++·算法
飞Link2 小时前
具身智能中 Wrapper 架构的深度解构与 Python 实战
开发语言·python·架构
喵叔哟2 小时前
15-文本分析与情感分析
微服务·.net
叫我一声阿雷吧2 小时前
JS 入门通关手册(21):原型链:JS 继承的底层原理
开发语言·javascript·前端面试·原型链·js继承·js进阶·js面向对象
猫墨*2 小时前
springboot3、knife4j-openapi3配置动态接口版本管理
java·开发语言
weixin_531651812 小时前
Python 渐进式学习指南
开发语言·windows·python
weixin_649555672 小时前
C语言程序设计第四版(何钦铭、颜晖)第八章指针之在数组中查找指定元素
c语言·开发语言