C# 方法和函数
本章将详细介绍 C# 中的方法(函数),包括方法的定义、调用、参数传递、重载等核心概念,帮助你编写模块化和可重用的代码。
方法基础
方法的定义
csharp
// 基本语法
访问修饰符 返回类型 方法名(参数列表)
{
// 方法体
return 返回值; // 如果返回类型不是 void
}
// 示例:无参数无返回值的方法
public static void SayHello()
{
Console.WriteLine("Hello, World!");
}
// 示例:有参数有返回值的方法
public static int Add(int a, int b)
{
return a + b;
}
// 示例:有参数无返回值的方法
public static void PrintMessage(string message)
{
Console.WriteLine($"消息: {message}");
}方法的调用
csharp
class Program
{
static void Main(string[] args)
{
// 调用无参数方法
SayHello();
// 调用有参数有返回值的方法
int result = Add(5, 3);
Console.WriteLine($"5 + 3 = {result}");
// 调用有参数无返回值的方法
PrintMessage("这是一条测试消息");
// 直接在表达式中使用方法返回值
Console.WriteLine($"10 + 20 = {Add(10, 20)}");
}
static void SayHello()
{
Console.WriteLine("Hello, World!");
}
static int Add(int a, int b)
{
return a + b;
}
static void PrintMessage(string message)
{
Console.WriteLine($"消息: {message}");
}
}
```###
返回类型
```csharp
// void - 无返回值
static void PrintInfo()
{
Console.WriteLine("这个方法没有返回值");
}
// 基本数据类型返回值
static int GetAge()
{
return 25;
}
static double CalculateArea(double radius)
{
return Math.PI * radius * radius;
}
static bool IsEven(int number)
{
return number % 2 == 0;
}
static string GetFullName(string firstName, string lastName)
{
return $"{firstName} {lastName}";
}
// 数组返回值
static int[] GetNumbers()
{
return new int[] { 1, 2, 3, 4, 5 };
}
// 对象返回值
static DateTime GetCurrentTime()
{
return DateTime.Now;
}参数传递
值传递(默认方式)
csharp
static void ModifyValue(int x)
{
x = 100; // 只修改局部副本
Console.WriteLine($"方法内 x = {x}");
}
static void Main()
{
int number = 10;
Console.WriteLine($"调用前 number = {number}");
ModifyValue(number);
Console.WriteLine($"调用后 number = {number}"); // 仍然是 10
}引用传递 (ref)
csharp
static void ModifyByRef(ref int x)
{
x = 100; // 修改原始变量
Console.WriteLine($"方法内 x = {x}");
}
static void Swap(ref int a, ref int b)
{
int temp = a;
a = b;
b = temp;
}
static void Main()
{
int number = 10;
Console.WriteLine($"调用前 number = {number}");
ModifyByRef(ref number);
Console.WriteLine($"调用后 number = {number}"); // 变成 100
// 交换两个变量
int x = 5, y = 15;
Console.WriteLine($"交换前: x = {x}, y = {y}");
Swap(ref x, ref y);
Console.WriteLine($"交换后: x = {x}, y = {y}");
}输出参数 (out)
csharp
static bool TryDivide(int dividend, int divisor, out double result)
{
if (divisor == 0)
{
result = 0; // out 参数必须赋值
return false;
}
result = (double)dividend / divisor;
return true;
}
static void GetNameParts(string fullName, out string firstName, out string lastName)
{
string[] parts = fullName.Split(' ');
firstName = parts.Length > 0 ? parts[0] : "";
lastName = parts.Length > 1 ? parts[1] : "";
}
static void Main()
{
// 使用 out 参数
if (TryDivide(10, 3, out double result))
{
Console.WriteLine($"除法结果: {result:F2}");
}
else
{
Console.WriteLine("除法失败");
}
// 内联声明 out 变量
if (TryDivide(15, 0, out double failResult))
{
Console.WriteLine($"结果: {failResult}");
}
else
{
Console.WriteLine("除零错误");
}
// 多个 out 参数
GetNameParts("John Doe", out string first, out string last);
Console.WriteLine($"名: {first}, 姓: {last}");
}输入参数 (in) - C# 7.2+
csharp
// in 参数用于大型结构体,避免复制开销
struct LargeStruct
{
public int Value1;
public int Value2;
public int Value3;
// ... 更多字段
}
static void ProcessLargeStruct(in LargeStruct data)
{
// 只能读取,不能修改
Console.WriteLine($"处理数据: {data.Value1}");
// data.Value1 = 100; // 编译错误:不能修改 in 参数
}
static void Main()
{
LargeStruct data = new LargeStruct { Value1 = 42 };
ProcessLargeStruct(in data);
}可变参数 (params)
csharp
static int Sum(params int[] numbers)
{
int total = 0;
foreach (int number in numbers)
{
total += number;
}
return total;
}
static void PrintMessages(string prefix, params string[] messages)
{
foreach (string message in messages)
{
Console.WriteLine($"{prefix}: {message}");
}
}
static void Main()
{
// 可以传递任意数量的参数
Console.WriteLine($"Sum() = {Sum()}"); // 0
Console.WriteLine($"Sum(1) = {Sum(1)}"); // 1
Console.WriteLine($"Sum(1, 2, 3) = {Sum(1, 2, 3)}"); // 6
Console.WriteLine($"Sum(1, 2, 3, 4, 5) = {Sum(1, 2, 3, 4, 5)}"); // 15
// 也可以传递数组
int[] numbers = { 10, 20, 30 };
Console.WriteLine($"Sum(array) = {Sum(numbers)}"); // 60
// 带前缀的多个消息
PrintMessages("INFO", "系统启动", "加载配置", "准备就绪");
}方法重载
基本重载
csharp
class Calculator
{
// 重载:不同参数数量
public static int Add(int a, int b)
{
return a + b;
}
public static int Add(int a, int b, int c)
{
return a + b + c;
}
// 重载:不同参数类型
public static double Add(double a, double b)
{
return a + b;
}
public static string Add(string a, string b)
{
return a + b;
}
// 重载:不同参数顺序
public static void PrintInfo(string name, int age)
{
Console.WriteLine($"姓名: {name}, 年龄: {age}");
}
public static void PrintInfo(int age, string name)
{
Console.WriteLine($"年龄: {age}, 姓名: {name}");
}
}
static void Main()
{
Console.WriteLine(Calculator.Add(5, 3)); // int 版本
Console.WriteLine(Calculator.Add(5, 3, 2)); // 三参数版本
Console.WriteLine(Calculator.Add(5.5, 3.2)); // double 版本
Console.WriteLine(Calculator.Add("Hello", "World")); // string 版本
Calculator.PrintInfo("Alice", 25); // string, int 版本
Calculator.PrintInfo(30, "Bob"); // int, string 版本
}重载解析规则
csharp
class OverloadDemo
{
public static void Method(int x) => Console.WriteLine("int");
public static void Method(double x) => Console.WriteLine("double");
public static void Method(object x) => Console.WriteLine("object");
public static void Method(int x, int y) => Console.WriteLine("int, int");
public static void Method(double x, double y) => Console.WriteLine("double, double");
static void Main()
{
Method(42); // 精确匹配:int
Method(3.14); // 精确匹配:double
Method("hello"); // 精确匹配:object
Method(42, 3.14); // 没有精确匹配,编译错误
Method((double)42, 3.14); // 显式转换:double, double
}
}可选参数和命名参数
可选参数
csharp
static void CreateUser(string name, int age = 18, string city = "北京", bool isActive = true)
{
Console.WriteLine($"用户: {name}, 年龄: {age}, 城市: {city}, 活跃: {isActive}");
}
static void Main()
{
// 使用所有默认值
CreateUser("Alice");
// 部分使用默认值
CreateUser("Bob", 25);
// 指定所有参数
CreateUser("Charlie", 30, "上海", false);
}命名参数
csharp
static void ConfigureServer(string host, int port, bool useSSL, int timeout)
{
Console.WriteLine($"服务器: {host}:{port}, SSL: {useSSL}, 超时: {timeout}秒");
}
static void Main()
{
// 位置参数
ConfigureServer("localhost", 8080, true, 30);
// 命名参数
ConfigureServer(host: "example.com", port: 443, useSSL: true, timeout: 60);
// 混合使用(命名参数必须在位置参数之后)
ConfigureServer("api.example.com", port: 8443, useSSL: true, timeout: 120);
// 改变参数顺序
ConfigureServer(timeout: 90, host: "test.com", useSSL: false, port: 80);
}局部函数 (C# 7.0+)
csharp
static void ProcessNumbers(int[] numbers)
{
// 局部函数:只在当前方法内可见
bool IsEven(int number)
{
return number % 2 == 0;
}
void PrintResult(string label, int count)
{
Console.WriteLine($"{label}: {count}");
}
// 使用局部函数
int evenCount = 0;
int oddCount = 0;
foreach (int number in numbers)
{
if (IsEven(number))
evenCount++;
else
oddCount++;
}
PrintResult("偶数个数", evenCount);
PrintResult("奇数个数", oddCount);
}
static void Main()
{
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
ProcessNumbers(numbers);
}递归方法
基本递归
csharp
// 计算阶乘
static long Factorial(int n)
{
if (n <= 1)
return 1; // 基础情况
else
return n * Factorial(n - 1); // 递归调用
}
// 计算斐波那契数列
static long Fibonacci(int n)
{
if (n <= 1)
return n;
else
return Fibonacci(n - 1) + Fibonacci(n - 2);
}
// 计算最大公约数(欧几里得算法)
static int GCD(int a, int b)
{
if (b == 0)
return a;
else
return GCD(b, a % b);
}
static void Main()
{
Console.WriteLine($"5! = {Factorial(5)}");
Console.WriteLine($"Fibonacci(10) = {Fibonacci(10)}");
Console.WriteLine($"GCD(48, 18) = {GCD(48, 18)}");
}尾递归优化
csharp
// 普通递归(可能导致栈溢出)
static long FactorialNormal(int n)
{
if (n <= 1)
return 1;
return n * FactorialNormal(n - 1);
}
// 尾递归版本
static long FactorialTail(int n, long accumulator = 1)
{
if (n <= 1)
return accumulator;
return FactorialTail(n - 1, n * accumulator);
}
// 迭代版本(推荐用于大数值)
static long FactorialIterative(int n)
{
long result = 1;
for (int i = 2; i <= n; i++)
{
result *= i;
}
return result;
}实践示例
示例 1:数学工具类
csharp
using System;
class MathUtils
{
// 判断是否为质数
public static bool IsPrime(int number)
{
if (number < 2) return false;
if (number == 2) return true;
if (number % 2 == 0) return false;
for (int i = 3; i * i <= number; i += 2)
{
if (number % i == 0)
return false;
}
return true;
}
// 计算两个数的最大公约数
public static int GCD(int a, int b)
{
while (b != 0)
{
int temp = b;
b = a % b;
a = temp;
}
return Math.Abs(a);
}
// 计算两个数的最小公倍数
public static int LCM(int a, int b)
{
return Math.Abs(a * b) / GCD(a, b);
}
// 计算数字的各位数字之和
public static int SumOfDigits(int number)
{
int sum = 0;
number = Math.Abs(number);
while (number > 0)
{
sum += number % 10;
number /= 10;
}
return sum;
}
// 判断是否为完全数
public static bool IsPerfectNumber(int number)
{
if (number <= 1) return false;
int sum = 1; // 1 是所有数的因子
for (int i = 2; i * i <= number; i++)
{
if (number % i == 0)
{
sum += i;
if (i != number / i) // 避免重复计算平方根
sum += number / i;
}
}
return sum == number;
}
static void Main()
{
Console.WriteLine("=== 数学工具演示 ===");
// 测试质数判断
Console.WriteLine("\n质数测试:");
int[] testNumbers = { 2, 3, 4, 17, 25, 29 };
foreach (int num in testNumbers)
{
Console.WriteLine($"{num} 是质数: {IsPrime(num)}");
}
// 测试最大公约数和最小公倍数
Console.WriteLine("\nGCD 和 LCM 测试:");
Console.WriteLine($"GCD(48, 18) = {GCD(48, 18)}");
Console.WriteLine($"LCM(48, 18) = {LCM(48, 18)}");
// 测试数字各位之和
Console.WriteLine("\n数字各位之和:");
Console.WriteLine($"SumOfDigits(12345) = {SumOfDigits(12345)}");
// 测试完全数
Console.WriteLine("\n完全数测试:");
for (int i = 1; i <= 30; i++)
{
if (IsPerfectNumber(i))
Console.WriteLine($"{i} 是完全数");
}
}
}示例 2:字符串处理工具
csharp
using System;
using System.Text;
class StringUtils
{
// 反转字符串
public static string Reverse(string input)
{
if (string.IsNullOrEmpty(input))
return input;
char[] chars = input.ToCharArray();
Array.Reverse(chars);
return new string(chars);
}
// 判断是否为回文
public static bool IsPalindrome(string input)
{
if (string.IsNullOrEmpty(input))
return true;
string cleaned = input.ToLower().Replace(" ", "");
return cleaned == Reverse(cleaned);
}
// 统计单词数量
public static int CountWords(string input)
{
if (string.IsNullOrWhiteSpace(input))
return 0;
string[] words = input.Trim().Split(new char[] { ' ', '\t', '\n', '\r' },
StringSplitOptions.RemoveEmptyEntries);
return words.Length;
}
// 首字母大写
public static string Capitalize(string input)
{
if (string.IsNullOrEmpty(input))
return input;
return char.ToUpper(input[0]) + input.Substring(1).ToLower();
}
// 移除重复字符
public static string RemoveDuplicates(string input)
{
if (string.IsNullOrEmpty(input))
return input;
StringBuilder result = new StringBuilder();
foreach (char c in input)
{
if (result.ToString().IndexOf(c) == -1)
result.Append(c);
}
return result.ToString();
}
static void Main()
{
Console.WriteLine("=== 字符串工具演示 ===");
string testString = "Hello World";
Console.WriteLine($"原字符串: '{testString}'");
Console.WriteLine($"反转: '{Reverse(testString)}'");
Console.WriteLine($"是否回文: {IsPalindrome(testString)}");
Console.WriteLine($"单词数量: {CountWords(testString)}");
Console.WriteLine($"首字母大写: '{Capitalize(testString)}'");
Console.WriteLine($"移除重复: '{RemoveDuplicates("programming")}'");
// 测试回文
string[] palindromes = { "level", "A man a plan a canal Panama", "race car" };
Console.WriteLine("\n回文测试:");
foreach (string p in palindromes)
{
Console.WriteLine($"'{p}' 是回文: {IsPalindrome(p)}");
}
}
}本章小结
本章详细介绍了 C# 中的方法和函数:
关键要点:
- 方法定义:访问修饰符、返回类型、方法名、参数列表
- 参数传递:值传递、引用传递(ref)、输出参数(out)、输入参数(in)
- 方法重载:相同方法名,不同参数签名
- 可选参数:提供默认值,简化方法调用
- 局部函数:方法内部定义的辅助函数
- 递归:方法调用自身解决问题
最佳实践:
- 方法应该职责单一,功能明确
- 使用有意义的方法名和参数名
- 避免过长的参数列表
- 合理使用方法重载
- 注意递归的终止条件
- 为公共方法添加 XML 文档注释
下一步: 在下一章中,我们将学习数组和集合,了解如何存储和操作多个数据项。