好的代码就像整洁的房间,每个物品都有固定的位置。方法让我们能够将代码组织成模块,提高可读性和复用性。
一、什么是方法?
【现实生活中的类比】
想象你有一个工具箱:
┌─────────────────┐
│ 工具箱 │
├─────────────────┤
│ 🔧 锤子 │
│ 🔨 扳手 │
│ 🪚 锯子 │
│ 📏 尺子 │
└─────────────────┘
工具箱 = 程序
每个工具 = 方法(函数)
使用工具 = 调用方法
【为什么要使用方法?】
不使用方法(代码重复):
// 计算 5 的圆面积double pi = 3.14;double r1 = 5;double area1 = pi * r1 * r1;Console.WriteLine($"半径为 {r1} 的面积:{area1}");// 计算 10 的圆面积double pi2 = 3.14;double r2 = 10;double area2 = pi2 * r2 * r2;Console.WriteLine($"半径为 {r2} 的面积:{area2}");// 计算 15 的圆面积double pi3 = 3.14;double r3 = 15;double area3 = pi3 * r3 * r3;Console.WriteLine($"半径为 {r3} 的面积:{area3}");
使用方法(简洁高效):
// 定义方法doubleCalculateCircleArea(double radius){ double pi = 3.14; return pi * radius * radius;}// 调用方法Console.WriteLine($"面积:{CalculateCircleArea(5)}");Console.WriteLine($"面积:{CalculateCircleArea(10)}");Console.WriteLine($"面积:{CalculateCircleArea(15)}");
【方法的好处】
✓ 避免代码重复:一次定义,多次调用
✓ 提高可读性:代码结构清晰,易于理解
✓ 便于维护:修改一处,所有调用处都更新
✓ 提高复用性:方法可以在不同地方使用
二、定义方法
【基本语法】
访问修饰符 返回值类型 方法名(参数列表){ // 方法体 return 返回值;}
【示例1:无返回值的方法】
// 输出欢迎信息voidSayHello(){ Console.WriteLine("欢迎来到编程世界!");}// 调用方法SayHello();
【示例2:带返回值的方法】
// 计算两个数的和intAdd(int a, int b){ int sum = a + b; return sum;}// 调用方法int result = Add(3, 5);Console.WriteLine(result); // 输出:8
【示例3:带多个参数的方法】
// 计算矩形面积doubleCalculateRectangleArea(double width, double height){ return width * height;}// 调用方法double area = CalculateRectangleArea(5, 3);Console.WriteLine($"面积:{area}"); // 输出:面积:15
三、方法的组成部分
【1. 返回值类型】
方法可以返回一个值,也可以不返回值。
// 返回整数intAdd(int a, int b){ return a + b;}// 返回布尔值boolIsEven(int number){ return number % 2 == 0;}// 不返回值voidPrintMessage(string message){ Console.WriteLine(message);}
【2. 参数】
参数是方法接收的输入值。
// 单个参数doubleCalculateSquare(double side){ return side * side;}// 多个参数doubleCalculateAverage(int a, int b, int c){ return (a + b + c) / 3.0;}// 无参数stringGetCurrentTime(){ return DateTime.Now.ToString();}
【3. 方法体】
方法体是方法实际执行的代码块。
voidPrintGrades(int score){ // 方法体 if (score >= 90) { Console.WriteLine("优秀"); } else if (score >= 60) { Console.WriteLine("及格"); } else { Console.WriteLine("不及格"); }}
四、调用方法
【语法】
方法名(参数列表);
【示例】
// 定义方法voidGreet(string name){ Console.WriteLine($"你好,{name}!");}// 调用方法Greet("张三"); // 输出:你好,张三!Greet("李四"); // 输出:你好,李四!
【调用带返回值的方法】
intAdd(int a, int b){ return a + b;}// 方式一:接收返回值int result = Add(3, 5);Console.WriteLine(result);// 方式二:直接使用返回值Console.WriteLine(Add(10, 20));
五、实践:将计算圆面积封装成方法
using System;namespace Week6Practice{ class Program { staticvoidMain(string[] args) { Console.WriteLine("===== 圆面积计算器 =====\n"); // 调用方法计算不同半径的面积 double area1 = CalculateCircleArea(5); Console.WriteLine($"半径 5 的面积:{area1:F2}"); double area2 = CalculateCircleArea(10); Console.WriteLine($"半径 10 的面积:{area2:F2}"); double area3 = CalculateCircleArea(15); Console.WriteLine($"半径 15 的面积:{area3:F2}"); // 计算用户输入的半径 Console.Write("\n请输入圆的半径:"); double inputRadius = double.Parse(Console.ReadLine()); double userArea = CalculateCircleArea(inputRadius); Console.WriteLine($"半径 {inputRadius} 的面积:{userArea:F2}"); } // 计算圆面积的方法 staticdoubleCalculateCircleArea(double radius) { double pi = 3.1415926; double area = pi * radius * radius; return area; } }}
输出:
===== 圆面积计算器 =====半径 5 的面积:78.54半径 10 的面积:314.16半径 15 的面积:706.86请输入圆的半径:8半径 8 的面积:201.06
【代码说明】
六、实践:判断奇偶数
using System;namespace Week6Practice{ class Program { staticvoidMain(string[] args) { Console.WriteLine("===== 奇偶数判断 =====\n"); // 测试多个数字 int[] numbers = { 1, 2, 3, 4, 5, 10, 15, 20 }; foreach (int num in numbers) { bool isEven = IsEven(num); string type = isEven ? "偶数" : "奇数"; Console.WriteLine($"{num} 是 {type}"); } } // 判断是否为偶数 staticboolIsEven(int number) { return number % 2 == 0; } }}
输出:===== 奇偶数判断 =====1 是 奇数2 是 偶数3 是 奇数4 是 偶数5 是 奇数10 是 偶数15 是 奇数20 是 偶数
七、实践:计算器
using System;namespace Week6Practice{ class Program { staticvoidMain(string[] args) { Console.WriteLine("===== 简易计算器 ====="); while (true) { Console.Write("\n请输入第一个数字(输入 q 退出):"); string input1 = Console.ReadLine(); if (input1.ToLower() == "q") break; Console.Write("请输入运算符(+、-、*、/):"); string op = Console.ReadLine(); Console.Write("请输入第二个数字:"); string input2 = Console.ReadLine(); double num1 = double.Parse(input1); double num2 = double.Parse(input2); double result = 0; // 调用不同的方法 switch (op) { case "+": result = Add(num1, num2); break; case "-": result = Subtract(num1, num2); break; case "*": result = Multiply(num1, num2); break; case "/": result = Divide(num1, num2); break; default: Console.WriteLine("无效的运算符!"); continue; } Console.WriteLine($"结果:{num1}{op}{num2} = {result}"); } Console.WriteLine("再见!"); } // 加法 staticdoubleAdd(double a, double b) { return a + b; } // 减法 staticdoubleSubtract(double a, double b) { return a - b; } // 乘法 staticdoubleMultiply(double a, double b) { return a * b; } // 除法 staticdoubleDivide(double a, double b) { if (b == 0) { Console.WriteLine("错误:除数不能为零!"); return 0; } return a / b; } }}
八、方法重载
同一个类中可以有多个同名方法,只要参数列表不同即可。
【示例】
// 计算两个数的和intAdd(int a, int b){ return a + b;}// 计算三个数的和(方法重载)intAdd(int a, int b, int c){ return a + b + c;}// 计算两个小数的和(方法重载)doubleAdd(double a, double b){ return a + b;}// 调用Console.WriteLine(Add(1, 2)); // 调用 int Add(int, int)Console.WriteLine(Add(1, 2, 3)); // 调用 int Add(int, int, int)Console.WriteLine(Add(1.5, 2.5)); // 调用 double Add(double, double)
【实践:输出信息】
// 无参数voidPrintInfo(){ Console.WriteLine("欢迎使用!");}// 一个参数voidPrintInfo(string name){ Console.WriteLine($"欢迎,{name}!");}// 两个参数voidPrintInfo(string name, int age){ Console.WriteLine($"欢迎,{name}!你今年 {age} 岁。");}// 调用PrintInfo(); // 输出:欢迎使用!PrintInfo("张三"); // 输出:欢迎,张三!PrintInfo("李四", 25); // 输出:欢迎,李四!你今年 25 岁。
九、方法命名规范
【命名规则】
✓ 推荐:
使用动词或动词短语
帕斯卡命名法(首字母大写)
语义清晰,见名知意
CalculateArea() // 计算面积GetUserInfo() // 获取用户信息SaveData() // 保存数据IsValidEmail() // 验证邮箱是否有效
✗ 不推荐:
area() // 太简单doSomething() // 含义不清calculate() // 不够具体
【常见方法命名前缀/后缀】
| | |
|---|
Get | | GetName() |
Set | | SetName() |
Is | | IsEven() |
Has | | HasPermission() |
Calculate | | CalculateArea() |
Convert | | ToString() |
Add | | AddItem() |
Remove | | RemoveItem() |
十、参数传递
【1. 值传递(默认)】
参数的值被复制到方法内部,不会影响原始变量。
voidChangeValue(int x){ x = 100; Console.WriteLine($"方法内 x = {x}"); // 100}int num = 10;ChangeValue(num);Console.WriteLine($"方法外 num = {num}"); // 10(不受影响)
【2. 引用传递(ref)】
使用 ref 关键字,方法可以修改原始变量。
voidChangeValue(refint x){ x = 100; Console.WriteLine($"方法内 x = {x}"); // 100}int num = 10;ChangeValue(ref num); // 注意调用时也要加 refConsole.WriteLine($"方法外 num = {num}"); // 100(已被修改)
【3. 输出参数(out)】
用于返回多个值。
void GetMinMax(int[] numbers, out int min, out int max){ min = numbers[0]; max = numbers[0]; foreach (int num in numbers) { if (num < min) min = num; if (num > max) max = num; }}int[] arr = { 3, 1, 4, 1, 5, 9, 2, 6 };int min, max;GetMinMax(arr, out min, out max);Console.WriteLine($"最小值:{min},最大值:{max}");// 输出:最小值:1,最大值:9
十一、实践:学生成绩管理系统
using System;using System.Collections.Generic;namespace Week6Practice{ class Program { staticvoidMain(string[] args) { List<string> names = new List<string>(); List<double> scores = new List<double>(); while (true) { Console.WriteLine("\n===== 学生成绩管理系统 ====="); Console.WriteLine("1. 添加学生"); Console.WriteLine("2. 查看所有学生"); Console.WriteLine("3. 计算平均分"); Console.WriteLine("4. 查找最高分"); Console.WriteLine("5. 退出"); Console.Write("请选择:"); string choice = Console.ReadLine(); switch (choice) { case "1": AddStudent(names, scores); break; case "2": DisplayStudents(names, scores); break; case "3": CalculateAverage(scores); break; case "4": FindHighestScore(names, scores); break; case "5": Console.WriteLine("再见!"); return; default: Console.WriteLine("无效选择!"); break; } } } // 添加学生 staticvoidAddStudent(List<string> names, List<double> scores) { Console.Write("请输入学生姓名:"); string name = Console.ReadLine(); Console.Write("请输入学生成绩:"); double score = double.Parse(Console.ReadLine()); names.Add(name); scores.Add(score); Console.WriteLine($"已添加学生:{name},成绩:{score}"); } // 显示所有学生 staticvoidDisplayStudents(List<string> names, List<double> scores) { if (names.Count == 0) { Console.WriteLine("暂无学生数据!"); return; } Console.WriteLine("\n===== 学生列表 ====="); for (int i = 0; i < names.Count; i++) { Console.WriteLine($"{i + 1}. {names[i]} - {scores[i]}"); } } // 计算平均分 staticvoidCalculateAverage(List<double> scores) { if (scores.Count == 0) { Console.WriteLine("暂无学生数据!"); return; } double sum = 0; foreach (double score in scores) { sum += score; } double average = sum / scores.Count; Console.WriteLine($"平均分:{average:F2}"); } // 查找最高分 staticvoidFindHighestScore(List<string> names, List<double> scores) { if (scores.Count == 0) { Console.WriteLine("暂无学生数据!"); return; } double maxScore = scores[0]; string topStudent = names[0]; for (int i = 1; i < scores.Count; i++) { if (scores[i] > maxScore) { maxScore = scores[i]; topStudent = names[i]; } } Console.WriteLine($"最高分:{maxScore},学生:{topStudent}"); } }}
十二、方法作为参数:Func 和 Action
【什么是委托?】
委托(Delegate)可以理解为"方法的容器"或"方法的引用"。就像变量可以存储数字一样,委托可以存储方法。
【为什么需要委托?】
想象你有一个计算器,需要支持不同的运算方式:
// 传统方式:每种运算写一个方法voidExecuteAdd(int a, int b){ Console.WriteLine(a + b);}voidExecuteMultiply(int a, int b){ Console.WriteLine(a * b);}
这种方式重复代码很多!如果用委托,可以让方法作为参数传递:
// 一个通用方法,接收另一个方法作为参数voidExecuteOperation(int a, int b, Func<int, int, int> operation){ Console.WriteLine(operation(a, b));}
【Action 和 Func 的区别】
| | | |
|---|
| Action | 无返回值 | Action<T1, T2, ...> | Action<int, int> |
| Func | 有返回值 | Func<T1, T2, ..., TResult> | Func<int, int, int> |
【Action:无返回值的委托】
语法:Action、Action<T>、Action<T1, T2> ...
// 1. 无参数的 ActionAction sayHello = () => Console.WriteLine("你好!");sayHello(); // 输出:你好!// 2. 一个参数的 ActionAction<string> greet = (name) => Console.WriteLine($"你好,{name}!");greet("张三"); // 输出:你好,张三!// 3. 两个参数的 ActionAction<int, int> printSum = (a, b) => Console.WriteLine($"和:{a + b}");printSum(5, 3); // 输出:和:8
【使用场景:传递一个不返回结果的操作】
voidProcessItems(int[] items, Action<int> processor){ foreach (int item in items) { processor(item); // 调用传入的方法 }}int[] numbers = { 1, 2, 3, 4, 5 };// 方式一:打印每个数字ProcessItems(numbers, num => Console.WriteLine($"数字:{num}"));// 方式二:打印每个数字的平方ProcessItems(numbers, num => Console.WriteLine($"平方:{num * num}"));// 方式三:判断奇偶ProcessItems(numbers, num =>{ string type = num % 2 == 0 ? "偶数" : "奇数"; Console.WriteLine($"{num} 是 {type}");});
输出:数字:1数字:2数字:3数字:4数字:5平方:1平方:4平方:9平方:16平方:251 是 奇数2 是 偶数3 是 奇数4 是 偶数5 是 奇数
【Func:有返回值的委托】
语法:Func<TResult>、Func<T, TResult>、Func<T1, T2, TResult> ...
注意:最后一个泛型参数永远是返回值类型!
// 1. 无参数,返回 intFunc<int> getRandom = () => new Random().Next(1, 100);Console.WriteLine(getRandom()); // 输出:随机数// 2. 一个参数,返回结果Func<int, int> square = x => x * x;Console.WriteLine(square(5)); // 输出:25// 3. 两个参数,返回结果Func<int, int, int> add = (a, b) => a + b;Console.WriteLine(add(3, 5)); // 输出:8// 4. 多个参数Func<int, int, int, int> sum = (a, b, c) => a + b + c;Console.WriteLine(sum(1, 2, 3)); // 输出:6
【使用场景:传递一个会返回结果的计算】
doubleCalculate(double a, double b, Func<double, double, double> operation){ return operation(a, b);}double num1 = 10, num2 = 5;// 使用不同的运算double sum = Calculate(num1, num2, (x, y) => x + y);Console.WriteLine($"和:{sum}");double product = Calculate(num1, num2, (x, y) => x * y);Console.WriteLine($"积:{product}");double power = Calculate(num1, num2, (x, y) => Math.Pow(x, y));Console.WriteLine($"幂:{power}");
十三、常用 Func 类型速查表
| |
|---|
Func<TResult> | |
Func<T, TResult> | |
Func<T1, T2, TResult> | |
Func<T1, T2, T3, TResult> | |
Func<T1, T2, T3, T4, TResult> | |
十四、常用 Action 类型速查表
| |
|---|
Action | |
Action<T> | |
Action<T1, T2> | |
Action<T1, T2, T3> | |
Action<T1, T2, T3, T4> | |
十五、什么时候使用 Action 和 Func?
✓ 适合使用的场景:
需要将方法作为参数传递给其他方法
需要根据不同情况执行不同的逻辑
需要计算一个值,但计算方式可以变化
使用 LINQ(第17章会学到)
✓ Action 适用场景:
只需要执行某个操作,不需要返回结果
遍历集合并对每个元素做处理
✓ Func 适用场景:
需要计算并返回结果
需要判断某个条件(返回 bool)
需要转换数据
【小贴士】
💡 Lambda 表达式简化写法:
// 完整写法Func<int, int> square = (x) => { return x * x; };// 简化写法(单语句可省略花括号和 return)Func<int, int> square = x => x * x;
💡 Action 和 Func 本质是委托类型:
// 这两种写法等价Action<int> print1 = x => Console.WriteLine(x);Action<int> print2 = new Action<int>(x => Console.WriteLine(x));
十六、本章总结