方法(函数)#
方法是将一段可复用的代码封装起来的单元。本篇覆盖:方法定义、引用传参(ref / out)、手写字符串方法、递归与重载。方法重载见 方法重载。
一、方法的定义#
| 要素 | 说明 |
|---|---|
| 访问修饰符 | public / private / internal / protected |
| 返回类型 | 方法执行完返回的数据类型,无返回值用 void |
| 方法名 | 遵循 PascalCase 命名规范 |
| 参数列表 | 方法接收的输入,可多个,用逗号分隔 |
代码组织技巧#
#region 字符串操作
// 使用 #region 折叠代码区域,便于组织代码结构
#endregion
/// <summary>
/// XML 文档注释,用于方法和类前面的说明
/// </summary>
二、引用传参(ref / out)#
1. 回顾:方法参数的赋值#
方法调用时,把实参赋值给形参:
| 参数类型 | 传递的是什么 |
|---|---|
| 值类型实参 | 保存的是值本身 |
| 引用类型实参 | 保存的是一个地址 |
2. 方法的传参两种方案#
- 值传递:形参是实参的一个副本,方法内修改形参不影响实参。
- 引用传递:使用
ref或out关键字,形参和实参指向同一个内存地址,方法内修改会影响实参。
3. ref 关键字#
public static double Dou(double a, double b, ref double c, ref double d)
{
c = a + b; // c 被赋值后,外部的 a3 也变了
d = a / b; // d 被赋值后,外部的 a4 也变了
double e = a * b;
return e;
}
// Main 方法中的调用
double a1 = 8.1, a2 = 2, a3 = 0, a4 = 0;
double b = quote.Dou(a1, a2, ref a3, ref a4);
// 结果:a3 = 10.1(8.1+2),a4 = 4.05(8.1/2),b = 16.2(8.1*2)
特点:
ref传入参数,调用方法时从外部向方法内部传入数据- 传入前必须已赋值
public static void RefStu(ref double x, ref double y)
{
Console.WriteLine($"得到的值是:{x},{y}");
x = 1231;
y = 23;
}
// 调用后,外部的 a1 变为 1231,a2 变为 23
4. out 关键字#
public static void OutStu(out double x, out double y)
{
x = 123;
y = 123412;
Console.WriteLine($"得到的值是:{x},{y}");
}
特点:
out传出参数,调用方法时从方法内部向外部传出数据- 传入前不用赋值(但不能在传入前取值)
- 在方法内部必须赋值
5. ref 与 out 的区别#
| 对比项 | ref |
out |
|---|---|---|
| 传入前是否必须赋值 | ✅ 必须赋值 | ❌ 不用赋值 |
| 方法内部是否必须赋值 | ❌ 不是必须 | ✅ 必须赋值 |
| 主要用途 | 传入数据(双向) | 传出数据(单向输出) |
6. 与 return 的对比#
return关键字:方法的返回值,但只能传出一个值。out/ref:可以同时传出多个值。
三、手写字符串方法(作业)#
对应源码:
Program.cs、StuM.cs
1. Contains — 判断字符串是否包含子串#
public static bool Contains(string source, string destination)
{
if (source.Length < destination.Length) return false;
if (destination == "") return false;
for (int i = 0; i <= source.Length - destination.Length; i++)
{
string str = "";
for (int j = i; j < destination.Length + i; j++)
{
str += source[j];
}
if (str == destination) return true;
}
return false;
}
两层循环:外层遍历 source 中每个可能的起始位置,内层从该位置取出与 destination 等长的子串进行比较。
2. StartStr — 判断是否以某子串开头#
// StuM.cs — 存在 bug 的版本
public static bool StartStr(string str1, string str2)
{
if (str1.Length < str2.Length) return false;
if (str2 == "") return false;
string str = "";
for (int i = 0; i < str2.Length; i++)
{
str += str[i]; // ❌ BUG:str 是空字符串,str[i] 会导致索引越界
// ✅ 正确写法:str += str1[i];
}
if (str2 == str) return true;
return false;
}
Bug 分析:
str是刚初始化的空字符串"",str[i]访问的是str的第 i 个字符,但str长度为 0,所以第一次循环(i=0)就会抛出IndexOutOfRangeException。应该改为str1[i]来取原字符串的字符。
3. EndStr — 判断是否以某子串结尾#
public static bool EndStr(string str1, string str2)
{
if (str1.Length < str2.Length) return false;
if (str2 == "") return false;
for (int i = 0; i <= str1.Length - str2.Length; i++)
{
string str3 = "";
for (int j = i; j < str2.Length - i; j++)
{
str3 += str1[j];
}
if (str3 == str2 && str1[str1.Length - str2.Length] == str2[0])
{
return true;
}
}
return false;
}
4. StuM.cs 字符串方法中的 Bug 汇总#
| 方法名 | 所在文件 | 问题代码 | 正确写法 | 后果 |
|---|---|---|---|---|
StartStr |
StuM.cs 第68行 |
str += str[i] |
str += str1[i] |
空字符串越界,运行时崩溃 |
EndtStr |
StuM.cs 第92行 |
str += str[i] |
str += str1[i] |
空字符串越界,运行时崩溃 |
两个方法犯的是同一个错误:把局部变量
str(用于拼接结果的空字符串)误写成了索引来源,应该访问的是参数str1。
5. Concat — 拼接字符串数组#
public static string Concat(string[] str00)
{
string str = "";
for (int i = 0; i < str00.Length; i++)
{
str += str00[i];
}
return str;
}
6. NineTable — 生成乘法表#
public static string NineTable(int num)
{
string n = "";
for (int i = 1; i <= num; i++)
{
for (int j = 1; j <= i; j++)
{
n += $"{j}×{i}={j * i}\t";
}
n += "\n";
}
return n;
}
生成指定行数的乘法表(下三角格式),例如
NineTable(9)输出完整的九九乘法表。
四、Main 方法调用示例#
static void Main(string[] args)
{
string[] str2 = { "123", "1wer", "1639812639" };
// 字符串操作
Console.WriteLine(Contains("12314", "12")); // true
Console.WriteLine(EndStr("12314", "1")); // 判断是否以 "1" 结尾
Console.WriteLine(Concat(str2)); // "1231wer1639812639"
// 引用传参
double a1 = 8.1, a2 = 2, a3 = 0, a4 = 0;
double b = quote.Dou(a1, a2, ref a3, ref a4);
Console.WriteLine($"{a3},{a4},{b}"); // 10.1, 4.05, 16.2
StuOut.RefStu(ref a1, ref a2);
Console.WriteLine($"最后得到{a1},{a2}"); // 最后得到1231,23
}
五、关键知识点总结#
| 知识点 | 说明 |
|---|---|
ref |
引用传参,传入前必须赋值,方法内可读写 |
out |
引用传参,传入前不用赋值,方法内必须赋值 |
return |
返回值,只能返回一个值 |
Contains |
手写字符串包含判断,双层循环遍历 |
StartStr |
判断字符串是否以某子串开头 |
EndStr |
判断字符串是否以某子串结尾 |
Concat |
拼接字符串数组 |
NineTable |
生成九九乘法表 |
#region |
代码折叠区域,便于组织代码结构 |
/// <summary> |
XML 文档注释,用于方法和类前面的说明 |
| StuM.cs Bug | StartStr 和 EndtStr 中 str[i] 应改为 str1[i],否则空字符串越界崩溃 |
相关笔记#
- String 字符串 — 字符串常用方法(内置 API)
- 方法重载 — 方法重载(Overload)
- 0718 自学练习总结 — 方法练习(题目 31-38)
- 循环控制语句 — return 结束整个方法