6.1 为什么需要方法?

6.1.1 没有方法的问题

csharp

// 没有方法:代码重复、臃肿、难以维护
static void Main()
{
    // 第一次计算两个数的和
    int a1 = 10, b1 = 20;
    int sum1 = a1 + b1;
    Console.WriteLine($"{a1} + {b1} = {sum1}");
    
    // 第二次计算两个数的和
    int a2 = 15, b2 = 25;
    int sum2 = a2 + b2;
    Console.WriteLine($"{a2} + {b2} = {sum2}");
    
    // 第三次...
    // 每次都要重复写同样的代码
}

6.1.2 有方法的解决方案

csharp

// 定义一个方法,封装"加法并输出"的功能
static void AddAndPrint(int a, int b)
{
    int sum = a + b;
    Console.WriteLine($"{a} + {b} = {sum}");
}

static void Main()
{
    AddAndPrint(10, 20);  // 一行代码解决问题
    AddAndPrint(15, 25);
    AddAndPrint(100, 200);
}

6.1.3 方法的定义

方法 = 一个具有名称的代码块,用于执行特定任务

text

方法的比喻:
┌─────────────────────────────────────────────────────────┐
│                    餐厅的"做菜"流程                        │
├─────────────────────────────────────────────────────────┤
│                                                         │
│   点菜单(参数)          菜品(返回值)                    │
│       ↓                    ↑                            │
│   ┌─────────────────────────────────────┐              │
│   │           做菜方法                    │              │
│   │  1. 洗菜                              │              │
│   │  2. 切菜                              │              │
│   │  3. 炒菜                              │              │
│   │  4. 调味                              │              │
│   │  5. 装盘                              │              │
│   └─────────────────────────────────────┘              │
│                                                         │
└─────────────────────────────────────────────────────────┘

6.2 方法的声明和调用

6.2.1 方法的基本语法

csharp

// 语法
[访问修饰符] [static] 返回值类型 方法名(参数列表)
{
    // 方法体:执行的代码
    return 返回值;  // 如果返回值类型不是 void,必须有 return
}

// 最简单的无参无返回值方法
static void SayHello()
{
    Console.WriteLine("Hello!");
}

// 有参数无返回值
static void Greet(string name)
{
    Console.WriteLine($"你好,{name}!");
}

// 有参数有返回值
static int Add(int a, int b)
{
    return a + b;
}

6.2.2 方法的各个部分

csharp

// 完整示例
static int CalculateSum(int start, int end)
// ↑      ↑            ↑      ↑      ↑
// 修饰符 返回值类型    方法名  参数1  参数2
{
    int sum = 0;
    for (int i = start; i <= end; i++)
    {
        sum += i;
    }
    return sum;  // 返回计算结果
}

各部分详解

部分 说明 示例
static 静态方法,可以直接通过类名调用 static
返回值类型 方法返回什么类型的数据,如果不返回用 void intstringdoublevoid
方法名 标识方法,使用 PascalCase 命名规范 CalculateSumGetName
参数列表 传入方法的数据,可以有多个,用逗号分隔 (int a, string b)
方法体 花括号内的代码 { ... }
return 返回值并结束方法 return sum;

6.2.3 调用方法

csharp

static void Main()
{
    // 调用无返回值方法
    SayHello();
    
    // 调用有参数方法
    Greet("张三");
    
    // 调用有返回值方法
    int result = Add(5, 3);
    Console.WriteLine($"5 + 3 = {result}");
    
    // 也可以直接使用返回值
    Console.WriteLine($"10 + 20 = {Add(10, 20)}");
}

6.2.4 方法的执行流程

text

Main 方法:
    ┌─────────────────────────────────────────┐
    │  int result = Add(5, 3);                │
    │       │                                  │
    │       │ 调用 Add 方法                     │
    │       ↓                                  │
    └───────┼─────────────────────────────────┘
            │
            ↓
    ┌─────────────────────────────────────────┐
    │  static int Add(int a, int b)           │
    │  {                                      │
    │      // a = 5, b = 3                    │
    │      int sum = a + b;  // sum = 8       │
    │      return sum;       // 返回 8         │
    │  }                                      │
    └───────┬─────────────────────────────────┘
            │
            │ 返回值 8
            ↓
    ┌─────────────────────────────────────────┐
    │  int result = 8;                        │
    └─────────────────────────────────────────┘

6.3 方法的参数

6.3.1 参数的基本使用

csharp

// 单个参数
static void PrintSquare(int number)
{
    Console.WriteLine($"{number} 的平方是 {number * number}");
}

// 多个参数
static double CalculateRectangleArea(double width, double height)
{
    return width * height;
}

// 调用
PrintSquare(5);  // 输出:5 的平方是 25
double area = CalculateRectangleArea(10.5, 20.3);

6.3.2 参数的传递机制

值类型参数传递的是值的副本,方法内修改不影响原变量

csharp

static void ChangeValue(int x)
{
    x = 100;  // 修改的是副本
    Console.WriteLine($"方法内部:x = {x}");
}

static void Main()
{
    int a = 10;
    ChangeValue(a);
    Console.WriteLine($"方法外部:a = {a}");
}
// 输出:
// 方法内部:x = 100
// 方法外部:a = 10  ← 没有改变!

6.3.3 ref 参数(引用传递)

使用 ref 关键字,传递的是变量的引用,方法内修改会影响原变量

csharp

static void ChangeValueByRef(ref int x)
{
    x = 100;  // 修改的是原变量
    Console.WriteLine($"方法内部:x = {x}");
}

static void Main()
{
    int a = 10;
    ChangeValueByRef(ref a);  // 调用时也要写 ref
    Console.WriteLine($"方法外部:a = {a}");
}
// 输出:
// 方法内部:x = 100
// 方法外部:a = 100  ← 被改变了!

6.3.4 out 参数(输出参数)

out 参数用于从方法返回多个值,调用前不需要初始化

csharp

// 返回多个值:商和余数
static void Divide(int dividend, int divisor, out int quotient, out int remainder)
{
    quotient = dividend / divisor;
    remainder = dividend % divisor;
}

// 经典的 TryParse 模式
static bool TryParseToInt(string input, out int result)
{
    try
    {
        result = Convert.ToInt32(input);
        return true;
    }
    catch
    {
        result = 0;
        return false;
    }
}

static void Main()
{
    // 使用 out 参数
    int q, r;
    Divide(17, 5, out q, out r);
    Console.WriteLine($"17 ÷ 5 = {q} 余 {r}");  // 17 ÷ 5 = 3 余 2
    
    // TryParse 模式
    string input = "123abc";
    if (TryParseToInt(input, out int number))
    {
        Console.WriteLine($"转换成功:{number}");
    }
    else
    {
        Console.WriteLine("转换失败");
    }
}

6.3.5 ref vs out 对比

特点 ref out
传入前是否需要初始化 需要 不需要
方法内是否必须赋值 不必 必须(返回前要赋值)
用途 修改传入的变量 返回额外的值
调用时写法 ref 关键字 out 关键字

csharp

// ref:传入前必须初始化
int refValue = 10;  // 必须初始化
MethodWithRef(ref refValue);

// out:传入前不需要初始化
int outValue;       // 可以不初始化
MethodWithOut(out outValue);  // 方法内必须赋值

6.3.6 默认参数(可选参数)

csharp

// 带默认值的参数必须放在参数列表的最后
static void Greet(string name, string greeting = "你好")
{
    Console.WriteLine($"{greeting},{name}!");
}

static void Main()
{
    Greet("张三");           // 使用默认值:你好,张三!
    Greet("李四", "晚上好"); // 使用传入值:晚上好,李四!
}

6.3.7 命名参数

调用时可以指定参数名称,不按位置传递

csharp

static void PrintPersonInfo(string name, int age, string city)
{
    Console.WriteLine($"姓名:{name},年龄:{age},城市:{city}");
}

static void Main()
{
    // 位置参数(按顺序)
    PrintPersonInfo("张三", 25, "北京");
    
    // 命名参数(可以不按顺序)
    PrintPersonInfo(city: "上海", name: "李四", age: 30);
    
    // 混合使用(位置参数必须在命名参数之前)
    PrintPersonInfo("王五", city: "广州", age: 28);
}

6.4 方法的返回值

6.4.1 返回值的基本使用

csharp

// 返回 int 类型
static int GetMax(int a, int b)
{
    if (a > b)
        return a;
    else
        return b;
}

// 返回 string 类型
static string GetGreeting(string name)
{
    return $"你好,{name}!欢迎回来。";
}

// 返回 bool 类型
static bool IsAdult(int age)
{
    return age >= 18;
}

// 调用
int max = GetMax(10, 20);
string greeting = GetGreeting("张三");
bool canVote = IsAdult(18);

6.4.2 void 方法(无返回值)

csharp

// void 表示不返回任何值
static void PrintBanner()
{
    Console.WriteLine("******************");
    Console.WriteLine("*  欢迎来到C#世界  *");
    Console.WriteLine("******************");
}

// 调用
PrintBanner();

// void 方法也可以使用 return(但不能返回值),用于提前结束
static void PrintNumbers(int max)
{
    if (max <= 0)
    {
        Console.WriteLine("参数无效");
        return;  // 提前结束
    }
    
    for (int i = 1; i <= max; i++)
    {
        Console.Write(i + " ");
    }
    Console.WriteLine();
}

6.4.3 返回数组

csharp

// 返回一个整型数组
static int[] GenerateRandomArray(int length, int min, int max)
{
    Random random = new Random();
    int[] array = new int[length];
    
    for (int i = 0; i < length; i++)
    {
        array[i] = random.Next(min, max + 1);
    }
    
    return array;
}

// 调用
int[] numbers = GenerateRandomArray(10, 1, 100);
Console.WriteLine($"随机数组:{string.Join(", ", numbers)}");

6.4.4 返回多个值(使用元组)

C# 7.0+ 支持元组语法,可以轻松返回多个值

csharp

// 使用元组返回多个值
static (int sum, int count, double average) CalculateStats(int[] numbers)
{
    int sum = 0;
    foreach (int num in numbers)
    {
        sum += num;
    }
    
    int count = numbers.Length;
    double average = count > 0 ? (double)sum / count : 0;
    
    return (sum, count, average);
}

static void Main()
{
    int[] scores = { 85, 92, 78, 90, 88 };
    
    // 接收元组返回值
    (int total, int num, double avg) = CalculateStats(scores);
    
    Console.WriteLine($"总数:{total}");
    Console.WriteLine($"个数:{num}");
    Console.WriteLine($"平均:{avg:F2}");
    
    // 也可以单独接收
    var stats = CalculateStats(scores);
    Console.WriteLine($"总和:{stats.sum}");
    Console.WriteLine($"平均:{stats.average:F2}");
}

6.5 方法的重载

6.5.1 什么是方法重载?

同一个类中,多个方法可以使用相同的名字,只要参数列表不同

csharp

// 同一个方法名 Add,不同的参数
static int Add(int a, int b)
{
    return a + b;
}

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

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

static string Add(string a, string b)
{
    return a + b;
}

// 调用时,编译器根据传入的参数自动选择合适的方法
static void Main()
{
    Console.WriteLine(Add(5, 3));        // 调用 int Add(int, int)
    Console.WriteLine(Add(5.5, 3.2));    // 调用 double Add(double, double)
    Console.WriteLine(Add(1, 2, 3));     // 调用 int Add(int, int, int)
    Console.WriteLine(Add("Hello", " World")); // 调用 string Add(string, string)
}

6.5.2 重载的规则

可以重载的情况

csharp

// 1. 参数个数不同
void Print(int a) { }
void Print(int a, int b) { }

// 2. 参数类型不同
void Print(int a) { }
void Print(string a) { }

// 3. 参数顺序不同
void Print(int a, string b) { }
void Print(string a, int b) { }

不能重载的情况

csharp

// ❌ 只有返回值类型不同,不能重载
int GetValue() { return 0; }
string GetValue() { return ""; }  // 编译错误

// ❌ 只有参数名称不同,不能重载
void Print(int x) { }
void Print(int y) { }  // 编译错误

// ❌ 只有 ref/out 区别,不能重载
void Process(ref int x) { }
void Process(out int x) { }  // 编译错误

6.5.3 重载的实际应用:Console.WriteLine

csharp

// Console.WriteLine 有 19 个重载版本
Console.WriteLine();                    // 输出空行
Console.WriteLine("Hello");            // 输出字符串
Console.WriteLine(123);                // 输出整数
Console.WriteLine(3.14);               // 输出小数
Console.WriteLine(true);               // 输出布尔值
Console.WriteLine("{0} + {1} = {2}", 1, 2, 3);  // 格式化输出

6.6 方法的递归

6.6.1 什么是递归?

递归 = 方法调用自身

csharp

// 递归的经典例子:阶乘
// n! = n × (n-1) × (n-2) × ... × 1
static int Factorial(int n)
{
    // 终止条件:基础情况
    if (n <= 1)
        return 1;
    
    // 递归调用:n! = n × (n-1)!
    return n * Factorial(n - 1);
}

// 执行过程:Factorial(5)
// Factorial(5) = 5 × Factorial(4)
// Factorial(4) = 4 × Factorial(3)
// Factorial(3) = 3 × Factorial(2)
// Factorial(2) = 2 × Factorial(1)
// Factorial(1) = 1
// 然后逐层返回:2×1=2, 3×2=6, 4×6=24, 5×24=120

6.6.2 递归的必要条件

csharp

// 递归必须满足:
// 1. 有终止条件(防止无限递归)
// 2. 每次递归调用都向终止条件靠近

// ✅ 正确示例:斐波那契数列
static int Fibonacci(int n)
{
    if (n <= 1) return n;      // 终止条件
    return Fibonacci(n - 1) + Fibonacci(n - 2);  // 向终止条件靠近
}

// ❌ 错误示例:没有终止条件
static void InfiniteRecursion()
{
    Console.WriteLine("无限递归");
    InfiniteRecursion();  // 栈溢出!
}

6.6.3 递归的应用场景

csharp

// 1. 遍历文件夹(目录树)
static void PrintDirectory(string path, int level = 0)
{
    string indent = new string(' ', level * 2);
    Console.WriteLine($"{indent}📁 {Path.GetFileName(path)}");
    
    try
    {
        // 遍历子目录
        foreach (string dir in Directory.GetDirectories(path))
        {
            PrintDirectory(dir, level + 1);
        }
        
        // 遍历文件
        foreach (string file in Directory.GetFiles(path))
        {
            Console.WriteLine($"{indent}  📄 {Path.GetFileName(file)}");
        }
    }
    catch (UnauthorizedAccessException)
    {
        Console.WriteLine($"{indent}  [无权限]");
    }
}

// 2. 汉诺塔问题
static void Hanoi(int n, char from, char to, char helper)
{
    if (n == 1)
    {
        Console.WriteLine($"移动盘子 1 从 {from} 到 {to}");
        return;
    }
    
    Hanoi(n - 1, from, helper, to);
    Console.WriteLine($"移动盘子 {n} 从 {from} 到 {to}");
    Hanoi(n - 1, helper, to, from);
}

6.6.4 递归 vs 循环

特点 递归 循环
代码简洁性 适合树形结构 适合线性问题
性能 较差(有函数调用开销) 较好
内存使用 多(每次调用占用栈空间)
风险 可能栈溢出 可能死循环
可读性 自然递归逻辑 需要手动维护状态

csharp

// 递归:代码简洁但性能差
static int SumRecursive(int n)
{
    if (n <= 0) return 0;
    return n + SumRecursive(n - 1);
}

// 循环:性能好但需要手动控制
static int SumLoop(int n)
{
    int sum = 0;
    for (int i = 1; i <= n; i++)
    {
        sum += i;
    }
    return sum;
}

6.7 局部函数(C# 7.0+)

在方法内部定义的方法,只能在所在方法内部使用

csharp

static void ProcessData(int[] numbers)
{
    // 局部函数
    bool IsEven(int n)
    {
        return n % 2 == 0;
    }
    
    int Square(int n)
    {
        return n * n;
    }
    
    // 使用局部函数
    foreach (int num in numbers)
    {
        if (IsEven(num))
        {
            Console.WriteLine($"{num} 是偶数,平方是 {Square(num)}");
        }
    }
}

static void Main()
{
    int[] data = { 1, 2, 3, 4, 5 };
    ProcessData(data);
    
    // IsEven(10);  // ❌ 错误:局部函数外部不可见
}

局部函数的优势

  • 限制作用域,只在需要的地方可见

  • 可以访问外部方法的局部变量

  • 适合递归(比 lambda 表达式更清晰)


6.8 综合示例

示例1:数学工具类

csharp

using System;

class MathTools
{
    // 判断是否为质数
    static bool IsPrime(int number)
    {
        if (number < 2) return false;
        if (number == 2) return true;
        if (number % 2 == 0) return false;
        
        int limit = (int)Math.Sqrt(number);
        for (int i = 3; i <= limit; i += 2)
        {
            if (number % i == 0) return false;
        }
        return true;
    }
    
    // 获取最大公约数(欧几里得算法)
    static int GCD(int a, int b)
    {
        while (b != 0)
        {
            int temp = b;
            b = a % b;
            a = temp;
        }
        return a;
    }
    
    // 获取最小公倍数
    static int LCM(int a, int b)
    {
        return a * b / GCD(a, b);
    }
    
    // 判断是否为回文数
    static bool IsPalindrome(int number)
    {
        string str = number.ToString();
        int left = 0, right = str.Length - 1;
        
        while (left < right)
        {
            if (str[left] != str[right]) return false;
            left++;
            right--;
        }
        return true;
    }
    
    static void Main()
    {
        Console.WriteLine($"17 是质数吗?{IsPrime(17)}");
        Console.WriteLine($"24 和 36 的最大公约数:{GCD(24, 36)}");
        Console.WriteLine($"24 和 36 的最小公倍数:{LCM(24, 36)}");
        Console.WriteLine($"12321 是回文数吗?{IsPalindrome(12321)}");
    }
}

示例2:学生管理系统的完整实现

csharp

using System;

class StudentManager
{
    static string[] names = new string[100];
    static int[] scores = new int[100];
    static int studentCount = 0;
    
    static void Main()
    {
        bool running = true;
        
        while (running)
        {
            ShowMenu();
            string choice = Console.ReadLine();
            
            switch (choice)
            {
                case "1":
                    AddStudent();
                    break;
                case "2":
                    ShowAllStudents();
                    break;
                case "3":
                    ShowStatistics();
                    break;
                case "4":
                    SearchStudent();
                    break;
                case "5":
                    SortByScore();
                    break;
                case "6":
                    running = false;
                    Console.WriteLine("感谢使用,再见!");
                    break;
                default:
                    Console.WriteLine("无效选择,请重新输入!");
                    break;
            }
            
            if (running && choice != "6")
            {
                Console.WriteLine("\n按任意键继续...");
                Console.ReadKey();
            }
        }
    }
    
    static void ShowMenu()
    {
        Console.Clear();
        Console.WriteLine("=== 学生管理系统 ===");
        Console.WriteLine("1. 添加学生");
        Console.WriteLine("2. 查看所有学生");
        Console.WriteLine("3. 统计信息");
        Console.WriteLine("4. 查找学生");
        Console.WriteLine("5. 按成绩排序");
        Console.WriteLine("6. 退出");
        Console.Write("请选择:");
    }
    
    static void AddStudent()
    {
        if (studentCount >= names.Length)
        {
            Console.WriteLine("学生数量已达上限!");
            return;
        }
        
        Console.Write("请输入学生姓名:");
        string name = Console.ReadLine();
        
        Console.Write("请输入学生成绩:");
        if (!int.TryParse(Console.ReadLine(), out int score))
        {
            Console.WriteLine("成绩输入无效!");
            return;
        }
        
        names[studentCount] = name;
        scores[studentCount] = score;
        studentCount++;
        
        Console.WriteLine($"成功添加学生:{name},成绩:{score}");
    }
    
    static void ShowAllStudents()
    {
        if (studentCount == 0)
        {
            Console.WriteLine("暂无学生数据!");
            return;
        }
        
        Console.WriteLine("\n所有学生列表:");
        Console.WriteLine("序号\t姓名\t成绩");
        Console.WriteLine("-----------------");
        
        for (int i = 0; i < studentCount; i++)
        {
            Console.WriteLine($"{i + 1}\t{names[i]}\t{scores[i]}");
        }
    }
    
    static void ShowStatistics()
    {
        if (studentCount == 0)
        {
            Console.WriteLine("暂无学生数据!");
            return;
        }
        
        int sum = 0, max = scores[0], min = scores[0];
        string maxName = names[0], minName = names[0];
        int passCount = 0, failCount = 0;
        
        for (int i = 0; i < studentCount; i++)
        {
            sum += scores[i];
            
            if (scores[i] > max)
            {
                max = scores[i];
                maxName = names[i];
            }
            if (scores[i] < min)
            {
                min = scores[i];
                minName = names[i];
            }
            
            if (scores[i] >= 60) passCount++;
            else failCount++;
        }
        
        double average = (double)sum / studentCount;
        
        Console.WriteLine("\n=== 统计信息 ===");
        Console.WriteLine($"学生总数:{studentCount}");
        Console.WriteLine($"总分:{sum}");
        Console.WriteLine($"平均分:{average:F2}");
        Console.WriteLine($"最高分:{max}({maxName})");
        Console.WriteLine($"最低分:{min}({minName})");
        Console.WriteLine($"及格人数:{passCount},及格率:{(double)passCount / studentCount * 100:F1}%");
        Console.WriteLine($"不及格人数:{failCount},不及格率:{(double)failCount / studentCount * 100:F1}%");
        
        // 成绩分布
        int[] levelCount = new int[5];  // A,B,C,D,F
        for (int i = 0; i < studentCount; i++)
        {
            if (scores[i] >= 90) levelCount[0]++;
            else if (scores[i] >= 80) levelCount[1]++;
            else if (scores[i] >= 70) levelCount[2]++;
            else if (scores[i] >= 60) levelCount[3]++;
            else levelCount[4]++;
        }
        
        Console.WriteLine("\n成绩分布:");
        Console.WriteLine($"A (90-100):{levelCount[0]}人");
        Console.WriteLine($"B (80-89):{levelCount[1]}人");
        Console.WriteLine($"C (70-79):{levelCount[2]}人");
        Console.WriteLine($"D (60-69):{levelCount[3]}人");
        Console.WriteLine($"F (<60):{levelCount[4]}人");
    }
    
    static void SearchStudent()
    {
        if (studentCount == 0)
        {
            Console.WriteLine("暂无学生数据!");
            return;
        }
        
        Console.Write("请输入要查找的学生姓名:");
        string searchName = Console.ReadLine();
        
        bool found = false;
        for (int i = 0; i < studentCount; i++)
        {
            if (names[i].Equals(searchName, StringComparison.OrdinalIgnoreCase))
            {
                Console.WriteLine($"找到学生:{names[i]},成绩:{scores[i]}");
                found = true;
            }
        }
        
        if (!found)
        {
            Console.WriteLine($"未找到名为“{searchName}”的学生。");
        }
    }
    
    static void SortByScore()
    {
        if (studentCount <= 1)
        {
            ShowAllStudents();
            return;
        }
        
        // 冒泡排序(按成绩降序)
        for (int i = 0; i < studentCount - 1; i++)
        {
            for (int j = 0; j < studentCount - i - 1; j++)
            {
                if (scores[j] < scores[j + 1])
                {
                    // 交换成绩
                    int tempScore = scores[j];
                    scores[j] = scores[j + 1];
                    scores[j + 1] = tempScore;
                    
                    // 同时交换姓名
                    string tempName = names[j];
                    names[j] = names[j + 1];
                    names[j + 1] = tempName;
                }
            }
        }
        
        Console.WriteLine("\n已按成绩从高到低排序:");
        ShowAllStudents();
    }
}

示例3:猜数字游戏(方法版)

csharp

using System;

class GuessNumberGame
{
    static Random random = new Random();
    static int secretNumber;
    static int attempts;
    static int maxAttempts = 10;
    
    static void Main()
    {
        bool playAgain = true;
        
        while (playAgain)
        {
            InitializeGame();
            PlayGame();
            playAgain = AskPlayAgain();
        }
        
        Console.WriteLine("感谢游玩,再见!");
    }
    
    static void InitializeGame()
    {
        secretNumber = random.Next(1, 101);
        attempts = 0;
        Console.Clear();
        Console.WriteLine("=== 猜数字游戏 ===");
        Console.WriteLine($"我已经想好了一个1-100之间的数字。");
        Console.WriteLine($"你有{maxAttempts}次机会猜中它!");
        Console.WriteLine();
    }
    
    static void PlayGame()
    {
        bool guessed = false;
        
        while (attempts < maxAttempts && !guessed)
        {
            int guess = GetPlayerGuess();
            attempts++;
            
            guessed = CheckGuess(guess);
            
            if (!guessed && attempts < maxAttempts)
            {
                GiveHint(guess);
            }
        }
        
        ShowResult(guessed);
    }
    
    static int GetPlayerGuess()
    {
        int guess;
        bool validInput = false;
        
        do
        {
            Console.Write($"请输入你的猜测(剩余{maxAttempts - attempts}次机会):");
            string input = Console.ReadLine();
            
            if (int.TryParse(input, out guess) && guess >= 1 && guess <= 100)
            {
                validInput = true;
            }
            else
            {
                Console.WriteLine("请输入1-100之间的有效数字!");
            }
        } while (!validInput);
        
        return guess;
    }
    
    static bool CheckGuess(int guess)
    {
        if (guess == secretNumber)
        {
            Console.WriteLine($"\n🎉 恭喜!你用了{attempts}次猜中了数字{secretNumber}!");
            return true;
        }
        return false;
    }
    
    static void GiveHint(int guess)
    {
        if (guess < secretNumber)
        {
            Console.WriteLine("太小了,再试试更大的数字!");
        }
        else
        {
            Console.WriteLine("太大了,再试试更小的数字!");
        }
        
        // 提供距离提示
        int difference = Math.Abs(secretNumber - guess);
        if (difference <= 5)
        {
            Console.WriteLine("🔥 非常接近了!");
        }
        else if (difference <= 10)
        {
            Console.WriteLine("⭐ 比较接近了!");
        }
    }
    
    static void ShowResult(bool guessed)
    {
        if (guessed)
        {
            // 根据猜中次数给出评价
            if (attempts <= 3)
                Console.WriteLine("🏆 天才!你是个猜数字高手!");
            else if (attempts <= 7)
                Console.WriteLine("👍 不错哦!继续加油!");
            else
                Console.WriteLine("😊 恭喜!下次可以尝试更快猜中!");
        }
        else
        {
            Console.WriteLine($"\n😭 很遗憾,机会用完了!");
            Console.WriteLine($"正确答案是:{secretNumber}");
        }
    }
    
    static bool AskPlayAgain()
    {
        Console.Write("\n是否继续游戏?(y/n):");
        string response = Console.ReadLine()?.ToLower();
        return response == "y" || response == "yes";
    }
}

6.9 常见错误与陷阱

错误1:返回值类型不匹配

csharp

static int GetNumber()
{
    return "123";  // ❌ 不能返回 string
}

static int GetNumber()
{
    // 没有 return 语句  // ❌ 非 void 方法必须有 return
}

错误2:方法内代码不可达

csharp

static void Test()
{
    return;
    Console.WriteLine("这行永远不会执行");  // ❌ 警告:不可达代码
}

错误3:递归没有终止条件

csharp

static void EndlessRecursion()
{
    EndlessRecursion();  // ❌ 栈溢出异常
}

错误4:ref/out 使用错误

csharp

static void Method(ref int x) { }

int a;
Method(ref a);  // ❌ ref 参数必须初始化

static void Method2(out int x) { }

int b = 10;
Method2(out b);  // out 参数不要求初始化,但初始值会被忽略

6.10 本章总结

方法设计原则

原则 说明
单一职责 一个方法只做一件事
方法名有意义 方法名应该清楚表达功能
参数不要太多 建议不超过5个参数
代码不要过长 建议不超过50行
避免副作用 方法应该只做名称所描述的事

方法签名

方法签名 = 方法名 + 参数类型和顺序(不包括返回值类型)

csharp

void Print(int a)          // 签名:Print(int)
void Print(string s)       // 签名:Print(string)
int Print(int a)           // ❌ 与第一个冲突,只有返回值不同

本章核心知识点

text

方法
├── 定义:static 返回值类型 方法名(参数列表)
├── 调用:方法名(参数)
├── 返回值:return 值(void 无返回值)
├── 参数传递
│   ├── 值传递(默认)
│   ├── ref(引用传递,双向)
│   └── out(输出参数,单向)
├── 参数特性
│   ├── 默认参数
│   ├── 命名参数
│   └── params(可变参数)
├── 重载:同名不同参
└── 递归:方法调用自身

6.11 练习题

基础题

  1. 编写一个方法 PrintRectangle(int width, int height),输出由 * 组成的矩形。

  2. 编写方法 bool IsEven(int number) 判断一个数是否为偶数。

  3. 编写方法 double CircleArea(double radius) 计算圆的面积。

  4. 编写方法 int Power(int base, int exponent) 计算 base 的 exponent 次方(不用 Math.Pow)。

应用题

  1. 编写方法 int[] GeneratePrimes(int max),返回不超过 max 的所有质数。

  2. 编写方法 string ReverseString(string input),返回反转

更多推荐