C#方法重载与递归:从基础到实战的20+案例解析

1. 方法重载:参数差异的艺术

1.1 基础语法与参数规则
public class Calculator  
{  
    // === 重载规则:参数类型/数量不同 ===  
    public int Add(int a, int b)  
    {  
        return a + b;  
    }  

    public double Add(double a, double b)  
    {  
        return a + b;  
    }  

    public int Add(int a, int b, int c)  
    {  
        return a + b + c;  
    }  
}  

// === 调用示例 ===  
var calc = new Calculator();  
Console.WriteLine(calc.Add(1, 2));        // 输出:3(int)  
Console.WriteLine(calc.Add(1.5, 2.5));    // 输出:4.0(double)  
Console.WriteLine(calc.Add(1, 2, 3));     // 输出:6(int)  

注释

  • 返回类型不影响重载,但参数列表必须不同;
  • 参数顺序不同(如Add(int a, double b)Add(double a, int b)算重载!

1.2 进阶技巧:可选参数与命名参数
public class Logger  
{  
    // === 可选参数(默认值) ===  
    public void Log(string message, int level = 1)  
    {  
        Console.WriteLine($"Level {level}: {message}");  
    }  

    // === 命名参数(调用时指定参数名) ===  
    public void Log(string message, string category, bool isCritical)  
    {  
        Console.WriteLine(  
            $"Category: {category}, Critical: {isCritical}, Message: {message}"  
        );  
    }  
}  

// === 调用示例 ===  
var logger = new Logger();  
logger.Log("Error occurred");               // 输出:Level 1: Error occurred  
logger.Log(category: "Security",            // 命名参数  
           isCritical: true,  
           message: "Unauthorized access");  
// 输出:Category: Security, Critical: True, Message: Unauthorized access  

注释

  • 可选参数需在末尾,且默认值只能在定义时设置;
  • 命名参数可打破参数顺序的限制,提升可读性。

1.3 泛型与重载的结合
public class GenericCalculator  
{  
    // === 泛型约束(要求类型实现IComparable) ===  
    public T Max<T>(T a, T b) where T : IComparable  
    {  
        return a.CompareTo(b) > 0 ? a : b;  
    }  

    // === 重载:处理数组参数 ===  
    public T Max<T>(T[] array) where T : IComparable  
    {  
        T max = array[0];  
        foreach (T item in array)  
        {  
            if (item.CompareTo(max) > 0) max = item;  
        }  
        return max;  
    }  
}  

// === 调用示例 ===  
var gc = new GenericCalculator();  
Console.WriteLine(gc.Max(5, 10));          // 输出:10  
Console.WriteLine(gc.Max(new int[] { 3, 1, 4 })); // 输出:4  

注释

  • 泛型约束确保类型支持比较操作;
  • 通过重载实现单个方法名处理不同参数类型。

2. 递归:自我调用的艺术

2.1 基础递归:阶乘与斐波那契
public class MathHelper  
{  
    // === 阶乘递归(基本情况:n=0或1) ===  
    public int Factorial(int n)  
    {  
        if (n <= 1) return 1; // 终止条件  
        return n * Factorial(n - 1); // 递归步骤  
    }  

    // === 斐波那契数列(优化版:记忆化缓存) ===  
    private Dictionary<int, int> _cache = new();  
    public int Fibonacci(int n)  
    {  
        if (n <= 1) return n;  
        if (_cache.TryGetValue(n, out int result)) return result;  
        result = Fibonacci(n - 1) + Fibonacci(n - 2);  
        _cache[n] = result;  
        return result;  
    }  
}  

// === 调用示例 ===  
var helper = new MathHelper();  
Console.WriteLine(helper.Factorial(5)); // 输出:120  
Console.WriteLine(helper.Fibonacci(10)); // 输出:55(优化后效率大幅提升)  

注释

  • 未优化的斐波那契递归时间复杂度为O(2^n),通过缓存可降至O(n);
  • 递归必须有终止条件,否则会栈溢出(StackOverflowException)。

2.2 递归与数据结构:二叉树遍历
public class TreeNode  
{  
    public int Value { get; set; }  
    public TreeNode Left { get; set; }  
    public TreeNode Right { get; set; }  

    public TreeNode(int value) => Value = value;  
}  

public class TreeTraversal  
{  
    // === 前序遍历(根-左-右) ===  
    public void PreOrder(TreeNode root)  
    {  
        if (root == null) return;  
        Console.Write(root.Value + " "); // 处理根节点  
        PreOrder(root.Left);            // 递归左子树  
        PreOrder(root.Right);           // 递归右子树  
    }  

    // === 后序遍历(左-右-根) ===  
    public void PostOrder(TreeNode root)  
    {  
        if (root == null) return;  
        PostOrder(root.Left);  
        PostOrder(root.Right);  
        Console.Write(root.Value + " ");  
    }  
}  

// === 构建二叉树并调用 ===  
var root = new TreeNode(1)  
{  
    Left = new TreeNode(2) { Left = new TreeNode(4), Right = new TreeNode(5) },  
    Right = new TreeNode(3) { Left = new TreeNode(6), Right = new TreeNode(7) }  
};  

var traversal = new TreeTraversal();  
traversal.PreOrder(root); // 输出:1 2 4 5 3 6 7  
traversal.PostOrder(root); // 输出:4 5 2 6 7 3 1  

注释

  • 递归天然适合树结构的深度优先遍历(DFS);
  • 通过改变处理根节点的顺序,可实现不同遍历方式。

3. 重载与递归的协同:高级场景

3.1 重载支持的递归函数
public class RecursiveCalculator  
{  
    // === 递归求和(基础版) ===  
    public int Sum(params int[] numbers)  
    {  
        if (numbers.Length == 0) return 0;  
        return numbers[0] + Sum(numbers.Skip(1).ToArray()); // 递归调用  
    }  

    // === 重载:支持链式调用 ===  
    public int Sum(int first, int second) => first + second;  

    public int Sum(int first, int second, int third)  
        => first + second + third;  
}  

// === 调用示例 ===  
var rc = new RecursiveCalculator();  
Console.WriteLine(rc.Sum(1, 2, 3)); // 输出:6(直接调用重载)  
Console.WriteLine(rc.Sum(new[] { 1, 2, 3, 4 })); // 输出:10(递归分解)  

注释

  • params 关键字允许变长参数,结合递归实现任意长度数组求和;
  • 重载方法简化了常见参数组合的调用。

3.2 递归与泛型的结合
public class GenericTree<T> where T : IComparable<T>  
{  
    public T Value { get; set; }  
    public GenericTree<T> Left { get; set; }  
    public GenericTree<T> Right { get; set; }  

    public GenericTree(T value) => Value = value;  
}  

public class TreeOperations<T> where T : IComparable<T>  
{  
    // === 递归查找元素 ===  
    public bool Contains(GenericTree<T> root, T value)  
    {  
        if (root == null) return false;  
        if (root.Value.CompareTo(value) == 0) return true;  
        return Contains(root.Left, value) || Contains(root.Right, value);  
    }  

    // === 重载:支持默认值 ===  
    public bool Contains(GenericTree<T> root)  
        => Contains(root, default(T)); // 默认查找默认值  
}  

// === 使用示例 ===  
var tree = new GenericTree<string>("A")  
{  
    Left = new GenericTree<string>("B"),  
    Right = new GenericTree<string>("C")  
};  

var operations = new TreeOperations<string>();  
Console.WriteLine(operations.Contains(tree, "B")); // 输出:True  

注释

  • 泛型约束确保类型支持比较操作;
  • 重载方法允许灵活调用,默认参数简化了常见场景。

4. 高级技巧与常见问题

4.1 重载决策机制的陷阱
public class Human  
{  
    public void Write(char value)  
    {  
        Console.WriteLine("char: " + value);  
    }  
}  

public class Male : Human  
{  
    // === 重载而非重写 ===  
    public void Write(int value)  
    {  
        Console.WriteLine("int: " + value);  
    }  
}  

// === 调用示例 ===  
var male = new Male();  
male.Write('a'); // 输出:int:97!而非父类的char:a  

// === 原因 ===  
// 重载决策优先选择子类的方法,即使参数类型不匹配!  
// 'a'的隐式转换为int(97)导致调用Male.Write(int)  

注释

  • 子类的重载方法会隐藏父类同名方法,需用new关键字显式声明;
  • 正确写法:public new void Write(char value)

4.2 递归的优化与替代方案
// === 尾递归优化(C#不支持,需手动改写为迭代) ===  
public int FactorialIterative(int n)  
{  
    int result = 1;  
    for (int i = 1; i <= n; i++)  
    {  
        result *= i;  
    }  
    return result;  
}  

// === 使用表达式树(Expression Tree)实现递归 ===  
public class ExpressionTreeExample  
{  
    public static Func<int, int> CreateFactorialFunc()  
    {  
        var n = Expression.Parameter(typeof(int), "n");  
        var one = Expression.Constant(1);  
        var condition = Expression.LessThanOrEqual(n, one);  
        var body = Expression.Condition(  
            condition,  
            one,  
            Expression.Multiply(n, Expression.Invoke(CreateFactorialFunc(), Expression.Subtract(n, one)))  
        );  
        return Expression.Lambda<Func<int, int>>(body, n).Compile();  
    }  
}  

注释

  • 尾递归在C#中无法优化,需手动改写为循环;
  • 表达式树可用于动态生成递归逻辑,但复杂度较高。

5. 企业级实战案例

5.1 动态配置解析(重载+反射)
public class ConfigParser  
{  
    // === 重载支持不同格式 ===  
    public void Parse(string configPath) => Parse(File.ReadAllText(configPath));  
    public void Parse(string configContent)  
    {  
        // 解析逻辑  
    }  

    // === 反射调用重载方法 ===  
    public void ParseDynamic(Type configType, params object[] args)  
    {  
        var method = GetType().GetMethod(  
            nameof(Parse),  
            BindingFlags.Instance | BindingFlags.Public  
        );  
        method.Invoke(this, args); // 根据参数类型选择重载  
    }  
}  

// === 调用示例 ===  
var parser = new ConfigParser();  
parser.Parse("config.json");        // 路径参数  
parser.Parse("{ \"key\": \"value\" }"); // 内容参数  
parser.ParseDynamic(typeof(string), "fallback.json"); // 动态调用  

5.2 二叉树序列化(递归+泛型)
public class TreeSerializer<T>  
{  
    public string Serialize(TreeNode<T> root)  
    {  
        if (root == null) return "null";  
        return $"[{root.Value}, {Serialize(root.Left)}, {Serialize(root.Right)}]";  
    }  

    public TreeNode<T> Deserialize(string data)  
    {  
        // 反序列化逻辑(递归构建树)  
        return null; // 省略实现细节  
    }  
}  

// === 使用示例 ===  
var serializer = new TreeSerializer<int>();  
var serialized = serializer.Serialize(root); // 输出:[1, [2, [4...]]]  

6. 常见问题与解决方案

6.1 重载方法无法调用?
// 错误:参数类型不匹配  
public void Print(int value) { ... }  
Print("Hello"); // 编译错误  

// 解决:添加重载或使用可选参数  
public void Print(string value) { ... }  
6.2 递归导致栈溢出?
// 避免大深度递归,改用迭代  
public int FactorialIterative(int n)  
{  
    int result = 1;  
    for (int i = 1; i <= n; i++) result *= i;  
    return result;  
}  
6.3 泛型约束冲突?
// 错误:无法约束为多个接口  
public void Process<T>(T item) where T : IComparable, ICloneable { ... }  

// 解决:确保类型同时实现多个接口  

微知著。”*

通过以上6大核心技术,你已掌握C#方法重载与递归的“全场景武器库”:

  • 方法重载:通过参数差异实现“一接口多实现”,提升代码复用性;
  • 递归:将复杂问题分解为简单子问题,优雅解决树遍历、分治算法等场景;
  • 高级技巧:结合泛型、反射、表达式树实现更灵活的设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值