/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */
#content_views .toc,
/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */
#content_views.markdown_views > p:empty:has(+ .toc),
#content_views.markdown_views > .toc + p:empty,
/* 富文本旧版目录标记 */
#content_views.htmledit_views #main-toc,
#content_views.htmledit_views #hr-toc,
#content_views.htmledit_views p[id*=\”-toc\”] {
display: none !important;
}
/* 目录去掉后,紧跟的首个标题不再多出一块上边距 */
#content_views.markdown_views > .toc + h1,
#content_views.markdown_views > .toc + h2,
#content_views.markdown_views > .toc + h3,
#content_views.markdown_views > .toc + h4,
#content_views.markdown_views > .toc + p:empty + h1,
#content_views.markdown_views > .toc + p:empty + h2,
#content_views.markdown_views > .toc + p:empty + h3,
#content_views.markdown_views > .toc + p:empty + h4 {
margin-top: 0 !important;
}
C# 修炼日记 · 2026 年 10 月 22 日
前五日,从练气入门一路打通数组与面向对象,属性、构造函数相继开光。今日峰主终于把目光落在修炼世界的"招法"上——方法(函数)。方法是封装好的一段功法:你刷一下身份证,闸机便自动判断买没买票;你把一个乱糟糟的数组丢进去,排序、转字符串一气呵成。峰主今日还传授了写方法的独门心法"反推法",以及不建对象也能直接调用的 static 静态功法。本卷理论篇(01)练"心明",把方法定义、四大分类、调用规则、重载、反推法与静态逐一吃透;实操篇(02)练"手熟",六道作业题全是方法的实战演练,其中重载、加权校验更是今日的重中之重。
第一部分 理论 01
今日功法速览
| 实例变量 / 局部变量 | 定义在类中 vs 定义在方法中:一个有默认值,一个必须手动初始化 |
| 方法(函数) | 封装一段完整功能,写在类的大括号内,写给别人用 |
| 返回类型 | void 无返回 / 具体数据类型有返回,二者写法不同 |
| 形参 / 实参 | 定义时的参数声明 vs 调用时传入的具体值,类型要匹配 |
| return | 有返回值的方法必写;无返回值也可写,作用是直接结束方法 |
| 方法四大分类 | 无参无返回值 / 有参无返回值 / 无参有返回值 / 有参有返回值 |
| 方法重载 | 方法名相同 + 参数列表不同,调用时按实参自动匹配 |
| 冒泡排序 Sort | 自定义升序排序,整型 / 浮点型各一版(重载) |
| ToString | 自定义数组转字符串输出,不再手动 for 遍历 |
| 反推法 | 先写调用逻辑,再逐步补方法实现——写方法的高级心法 |
| 身份证校验算法 | 前 17 位 × 权重求和 → 取模 11 → 映射出校验字符 |
| 静态 static | 类名直接点调用,无需创建对象 |
第一章 昨日复盘:属性封笔,方法登台
开讲之前,峰主先把昨日属性收了个尾。昨日讲了类与对象,属性着墨颇多,方法几乎没讲——今日重点就是方法。
属性昨日已经悟透几件事:
- 一个读写属性如果不带任何条件,它底层自动生成对应的私有字段,只是那行 private int _id; 不显示出来而已;
- 属性只有两类:可读可写(有 get 有 set)和只读(只有 get),不存在只写;
- 后续实际开发里,带条件的属性写得极少,一行 public int Id { get; set; } 就完事,不需要自己定义私有变量,直接公开属性。
峰主叮嘱:属性的门道昨日已尽,今日的主角是方法,全体竖起耳朵。
第二章 变量住哪,命就不同:实例变量 vs 局部变量
昨日有一个没展开的细节:变量写的位置不同,效果完全不同。峰主新建 OPDAY0201 项目,加了一个 stu 类,里面写一个 public int A;;又在 Test() 方法里写一个 int a;。两者一对比,高下立判:
class Stu
{
public int A; // 写在类里:实例变量(又叫成员变量、全局变量、属性)
public void Test()
{
// int a; // 写在方法里:局部变量
Console.WriteLine(A); // OK:对象创建后 A 已自动初始化,默认值 0
// Console.WriteLine(a); // 报错:局部变量不初始化,不能直接使用
}
}
| 定义位置 | 类的大括号内 | 方法的大括号内 |
| 有无初始值 | 有(创建对象时自动初始化) | 无(必须手动赋值才能用) |
| 使用范围 | 当前类的所有普通方法都能用 | 只能在定义它的方法内用 |
关键在"初始化"三个字。这个 A 写在类里时并没有值,它要等到"出生"那一刻才有——也就是 new Stu() 创建对象的那一刻,new 关键字顺手把类里的所有实例变量初始化了一遍。所以不创建对象,A 根本不存在;创建了对象,A 就有默认值 0。回想数组 int[] arr = new int[10],十个元素个个有默认值——new 关键字的作用就是初始化,万物同源。
而方法里的局部变量没人给它初始化,你不赋值就用,编译器直接红叉。
峰主叮嘱:这个变量叫法很多,属性、成员变量、实例变量、全局变量都是它,说哪个都不算错,但心里要清楚——它们指的是同一个东西:定义在类里的变量。日后学静态变量,三者还要拿来做一次大对比,伏笔先埋下。
峰主伏笔:从今日起写作业,一个项目就能写完所有题,不必一题一个项目——这正是有了类的好处。
第三章 方法是什么:一段被封装的功法
方法的定义就一句话:封装了一段完整功能。它是写在类的大括号里面的,不能脱离类单独存在。
峰主连打三个比方,务必吃透:
既然方法是写给别人用的,修饰词就必须是 public(公开)。写个 private 方法别人根本调不到,那写了还有什么意义?
峰主叮嘱:以后去公司,你的活就是写方法——把一段任务封装好,别人拿来就用。
第四章 方法定义五要素
一个方法由五部分组成,缺一不可:
public int Add(int a, int b)
{
return a + b;
}
| 修饰词 | 默认 public,公开给别人调用 |
| 返回类型 | 无返回写 void;有返回写返回的数据类型(int、double、string……) |
| 方法名 | 见名知义 + 首字母大写 |
| 形参列表 | 小括号里的变量声明,可以有 0 个或多个,多个用逗号隔开 |
| 方法体 | 大括号里的具体实现;有返回值必须写 return,且返回内容与声明类型匹配 |
- 返回类型:峰主用"让妈妈做蛋炒饭"类比——无返回相当于妈妈让你自己滚下去炒(void,默默做事不交结果);有返回相当于妈妈把炒好的蛋炒饭端给你(返回一个整数、小数、字符串……)。返回类型写成什么,取决于方法最终返回什么。
- 方法名:见名知义、首字母大写。峰主点名批评:昨天不少人方法名没大写,从今天起所有方法名必须首字母大写,养成习惯,否则日后是致命的打击。
- 形参:就是变量的声明,只是"形式上的参数",相当于留一个口子接收外面传进来的东西,别人传什么你就答什么。
- return:有返回值的方法必写;return 的返回内容要和声明时的数据类型匹配。
峰主叮嘱:这五要素就是方法的"开炉之法",往后写方法全都照着这套来。
第五章 方法四大分类与调用规则
方法按"有没有参数、有没有返回值"分成四大类:
| 无参无返回值 | public void Method01() | 低 |
| 有参无返回值 | public void Method02(int a) | 高 |
| 无参有返回值 | public double Method03() | 低 |
| 有参有返回值 | public int Method04(int a, int b) | 高 |
课堂逐一演示(以下代码均可编译运行):
class Stu
{
// 无参无返回值
public void Method01()
{
Console.WriteLine("你好");
}
// 有参无返回值:形参 a 直接用,无需额外赋值
public void Method02(int a)
{
Console.WriteLine(a);
}
// 无参有返回值:必须有 return,返回 5.6
public double Method03()
{
return 5.6;
}
// 有参有返回值:return a + b 的和
public int Method04(int a, int b)
{
return a + b;
}
}
调用时三条铁律:
IDE 里怎么认这些"招法"图标:方法是五边形里一个 Y,属性是扳手,字段是长方形——一看便知。方法调用后面永远带小括号 (),属性调用不带。
运行效果:
Method02(7) -> 7
Method03() -> 5.6
Method04(5,6) -> 11
峰主叮嘱:还有个容易走火的地方——return 和 break 不是一回事。break 只是退出循环,return 是直接结束整个方法,return 后面的代码永远执行不到(会变灰)。有返回值的方法写 return 值;,无返回值的方法也可以写一个光秃秃的 return; 提前收工。
第六章 方法重载:同名不同招
场景来了:Method04 只能求两个整数的和。想求两个小数怎么办?再写一个 double 版本?方法名能不能还用 Method04?
能。方法名一致、参数列表不同,就叫方法的重载。
峰主新建数学类 Mash,演示了一整套重载:
class Mash
{
// 求两个整数的和
public int Sum(int a, int b)
{
return a + b;
}
// 重载:求两个小数的和
public double Sum(double a, double b)
{
return a + b;
}
// 重载:求数组的和
public int Sum(int[] a)
{
int sum = 0;
for (int i = 0; i < a.Length; i++)
{
sum += a[i];
}
return sum;
}
}
调用时编译器按实参自动挑版本:传 3, 4 走整数版;传 3.0, 4.5 走小数版;传数组走数组版。参数列表相同就会报错——编译器不知道你传两个整数时该调哪一个;只要参数列表不同(数量不同、类型不同都算),随便写几个都不冲突。
Mash m = new Mash();
Console.WriteLine(m.Sum(3, 4)); // 7
Console.WriteLine(m.Sum(3.0, 4.5)); // 7.5
Console.WriteLine(m.Sum(new int[]{1,2,3,4,5})); // 15
为什么要有重载?因为功能相同、实现不同的事,就该共用一个名字——都在求和,凭什么一个叫 Sum 一个叫 Add?系统的 Console.WriteLine 就是重载大户:输出整数、小数、字符串、布尔都有对应版本,唯独没有无参版本,所以 Console.WriteLine(); 直接报错。Random.Next() 也是重载:传一个参数取 0 到 n,传两个参数取 n 到 m。
峰主伏笔:重载不只用在方法上,构造函数也能重载。方法重载 + 冒泡排序 + 转字符串的组合拳马上就来——这正是今天课堂布置的实操任务,也是你作业题 5 的同一招。
第七章 反推法:身份证校验实战
7.1 先讲"方法没实现"的教训
峰主先演示了一个反例:项目经理丢给你一个排序方法,你"已有一个方法"却压根没实现(方法体是空的),调用后数组输出顺序纹丝不动——排序根本没起作用。写方法,光有壳子不行,必须把实现填上。整型数组升序用冒泡:
public void Sort(int[] arr)
{
for (int i = 0; i < arr.Length – 1; i++)
{
for (int j = 0; j < arr.Length – 1 – i; j++)
{
if (arr[j] > arr[j + 1])
{
int t = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = t;
}
}
}
}
写完 int 版,复制一份把 int 改成 double,浮点数组也能排——这就是重载的实战。
再看"数组转字符串":直接输出数组只会得到一串地址,要的是 4,34,224,422,542,4244 这样的字符串。那就遍历 + 拼接:
public string ToString(int[] arr)
{
string s = "";
for (int i = 0; i < arr.Length; i++)
{
s += arr[i];
if (i < arr.Length – 1)
{
s += ",";
}
}
return s;
}
有了它,Main 里一句 Console.WriteLine(arrTool.ToString(arr)); 就完事,再也不用手动 for 循环输出了——这就是方法的价值:把常用的活儿封装起来,拿来就用。同样的,复制一份把参数换成 double[] 就是浮点版重载。
运行效果(以课堂示例数组 {8,3,4,5,4,2,2,2,4,4} 演示):
排序后输出:2,2,2,3,4,4,4,4,5,8
7.2 经典案例:验证身份证合法性
峰主抛出今日最经典的案例:身份证合法性校验。身份证 18 位由四段组成——前 6 位地址码(行政区划)、8 位出生日期、3 位顺序码(奇数男、偶数女)、最后 1 位校验码。而最后一位不是拍脑袋定的,是由前 17 位算出来的:
- 前 17 位分别乘以固定权重:7 9 10 5 8 4 2 1 6 3 7 9 10 5 8 4 2;
- 加权求和,再对 11 取模(sum % 11);
- 余数 0~10 依次映射校验字符:1 0 X 9 8 7 6 5 4 3 2。
7.3 反推法:先写调用方,再补方法
峰主强调:写方法最高级的心法是反推法——不知道方法怎么写没关系,先知道要实现什么,把"调用逻辑"写好,报错的地方再一个个补方法。
像高铁闸机一样,程序只需"刷身份证":输入前 17 位 → 算出校验字符 → 输入最后一位 → 比较。调用方先写成这样:
Card card = new Card();
Console.WriteLine("请输入身份证的前17位");
string s = Console.ReadLine(); // 第 1 步:输入前 17 位
char ch = card.YanZheng(s); // 第 2 步:算出校验字符(方法待补)
Console.WriteLine("请输入身份证的最后一位");
char ch1 = char.Parse(Console.ReadLine()); // 第 3 步:输入最后一位
if (ch1 == ch)
Console.WriteLine("身份证合法");
else
Console.WriteLine("身份证不合法");
card.YanZheng(s) 报错?那就去补这个方法,一步步反推:
class Card
{
// 反推第 1 层:前17位 × 权重求和 → 取模11 → 映射字符
public char YanZheng(string str)
{
int[] arr = new int[17] { 7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2 };
long sum = Sum(str, arr); // 反推第 2 层:求和的方法
long a = sum % 11;
char c = GetChar(a); // 反推第 3 层:余数转字符的方法
return c;
}
// 字符串的每一位数字 × 权重,累加
public long Sum(string str, int[] arr)
{
long[] arr1 = Parse(str); // 反推第 4 层:字符串转数字数组
long sum = 0;
for (int i = 0; i < arr1.Length; i++)
{
sum += arr1[i] * arr[i];
}
return sum;
}
// 17 位字符串 → 数字数组(17 位已超过 int 上限,用 long)
public long[] Parse(string s)
{
long[] arr = new long[17];
long l = long.Parse(s);
int index = 16;
while (l > 0)
{
arr[index] = l % 10; // 取个位
l /= 10; // 去掉个位
index—; // 下标往前挪
}
return arr;
}
// 余数 → 校验字符
public char GetChar(long a)
{
char[] c = new char[11] { '1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2' };
return c[(int)a];
}
}
为什么要用 long? 17 位数字早就爆了 int 的上限,只能用 long。课堂上峰主就栽在这里:一开始用 int 强转,打桩测试(临时输出中间变量排查,就叫打桩测试)发现第 4 位之后数据全错——long 强转成 int 出了乱子,最后统一改成 long 类型,一次通过。写代码要养成"先想类型会不会溢出"的习惯。
运行效果(示例前 17 位 11010519491231002,加权和 167,167 % 11 = 2,映射校验字符 ‘X’):
请输入身份证的前17位
11010519491231002
请输入身份证的最后一位
X
身份证合法
峰主叮嘱:反推法的精髓是"每一层都看得清清楚楚"——验证合法性 → 求校验字符 → 加权求和 → 转数组,每一环封装成一个方法,读代码像读账本。你的作业题 6(EAN-13 条码校验)就是这套加权求和的亲兄弟。
第八章 静态:不建对象也能用的功法
前六天学的变量、方法,都要"先 new 对象、再点着用"。今天峰主再传一招——static(静态)。
- 实例变量 / 实例方法:不加 static,必须 new 出对象,对象名.变量/方法;
- 静态变量 / 静态方法:加 static,也叫类变量 / 类方法,不用创建对象,直接 类名.变量/方法。静态方法里只能用静态变量,不能用未实例化的实例变量。
回头看,其实从第一天起你就在用静态方法:
| Console.WriteLine(…) | Console 是类名,WriteLine 是静态方法 |
| Array.Sort(arr)、Array.Resize(…) | Array 类是静态方法大户,排序调大小现成的 |
| Math.Abs(…)、Math.Pow(…) | Math 类的静态方法,取绝对值、求幂拿来就用 |
| Random r = new Random(); r.Next(); | 唯一要先 new 的——它是实例方法 |
这就是为什么学了 static 要看懂别人的代码:官方早把 Array、Math、Console 封装成静态功法,直接 类名.点 就完事;没有现成方法时,才自己手写。
峰主还演示了自定义封装:原生数组没有直接求最大值的方法,那就建一个 ArrayDemo 类自己封装:
class ArrayDemo
{
public int GetMax(int[] a)
{
ArrayTool.Sort(a); // 先升序排序
return a[a.Length – 1]; // 最后一个元素就是最大值
}
public int GetMaxIndex(int[] a)
{
if (a.Length == 0)
{
return –1; // 空数组兜底,避免无返回值
}
int max = GetMax(a);
for (int i = 0; i < a.Length; i++)
{
if (a[i] == max)
{
return i; // 多个最大值时返回第一个
}
}
return –1;
}
}
(示例数组 {3, 8, 5, 8, 1} 实测:GetMax → 8;但因为 GetMax 内部先排了序,数组已变成 {1, 3, 5, 8, 8},所以 GetMaxIndex → 3——排序会改动原数组,这副作用日后要留心。)
峰主叮嘱:本次作业不需要用 static,方法统一按实例方法写(修饰词 public 即可);讲 static 只是为了让你看懂 Console.WriteLine、Array.Sort 为什么能直接"类名点"调用,免得日后疑惑。
峰主伏笔:方法、属性、构造函数——类里这三样正一一揭开,明日继续。
走火入魔预警
| 局部变量没初始化就用 | 方法里 Console.WriteLine(a); 编译报错 | 先 int a = 0; 赋值再用;类中变量靠 new 初始化 |
| 有返回值方法忘写 return | public int Sum(…) 缺 return 报错 | 有返回值必写 return 值;,类型与声明一致 |
| 方法名不按规范 | public void show() 小写开头的旧习 | 首字母大写 + 见名知义:Show() |
| 形参实参类型不匹配 | 给 int a 传 7.8 报错 | 类型一致,或传可隐式转换的 byte、short |
| return 与 break 混为一谈 | 想在方法中间用 break 提前收工 | return 结束整个方法;break 只退出循环 |
| 重载参数列表相同 | 写两个 Sum(int, int) 报错 | 同名 + 参数列表不同(数量/类型不同) |
| 身份证 17 位用 int 存 | int.Parse 溢出报错 | 用 long.Parse |
| long 强转 int 数据错乱 | (int)(l % 10) 中间数据全错 | 直接统一用 long 类型,避免强转 |
| 方法只有壳没有实现 | 空方法调用后"没反应" | 先填方法体再调用(冒泡/拼接写完整) |
| 排序副作用改原数组 | GetMax 排序后 GetMaxIndex 结果变了 | 记住 Array.Sort 会改动原数组,留意调用顺序 |
今日修炼总结
今日心法,可归纳为八层:
峰主有言:方法的修炼重在一个"封"字——把功能封起来,把调用露出去。今日八层心法若只记住一句,就记"有返回值先接收、再输出;重载同名不同参"。
第二部分 实操 02
理论既明,今日正式上手方法实战。峰主说今天的作业要自己动手把方法一个个"搓"出来:判断闰年、登录校验、交换变量、数组求和、重载取最值、条码校验——六道题几乎覆盖了方法的所有用法。以下为今日修炼实录,全部功法均已在 .NET 控制台应用中编译运行通过,运行效果均为真实跑出的输出。
今日功法速览
| 方法封装 | 把判断、计算、交换逻辑写进方法,Main 里只负责调用 |
| 属性 set 判断 | 登录校验写在 set 里,输入即拦截 |
| 重载 ZSum | int / double / char 三版同名方法取最大值 |
| 加权求和 | EAN-13 校验位算法,与理论篇身份证校验同源 |
| 值传递 | 方法内交换变量不影响实参(题 3 的坑) |
基础题一:平年还是闰年
【题目要求】 写一个方法,判断是平年还是闰年:能被 4 整除不能被 100 整除,或者能被 400 整除。
【修炼思路】 建一个 Year 类,写一个 Pdyear(int year) 方法,把闰年的两个条件用 &&、|| 串起来,满足条件返回"闰年",否则返回"平年"。这是典型的有参有返回值方法——传一个年份进去,返回一个判断结果。
【代码】
//类
class Year
{
//属性
public string Pdyear(int year)
{
//判断
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)
{
return "闰年";
}
return "平年";
}
}
//实例化
Year a = new Year();
//调用Pdyear方法
string year = a.Pdyear(2026);
Console.WriteLine(year);
【运行效果】
平年
(再验一发 2024:Pdyear(2024) 输出 闰年——2024 能被 4 整除且不能被 100 整除。)
【修炼要点】 % 取余判断整除:year % 4 == 0 表示能被 4 整除;&& 优先级高于 ||,整条判断写成 year % 4 == 0 && year % 100 != 0 || year % 400 == 0 就是"(能被4整除 且 不能被100整除)或 能被400整除"。方法名 Pdyear(判断年)+ 首字母大写,符合见名知义规范。
基础题二:登录校验
【题目要求】 分别提示用户输入用户名和密码,写一个方法判断用户输入是否正确,返回给用户一个登录结果,并且还要单独返回登录信息:用户名错误或密码错误时,除了返回登录结果,还要返回"用户错误"或"密码错误"。
【修炼思路】 建一个 User 类,把判断写进属性的 set 里——用户名给 Name 属性,密码给 Password 属性,赋值的一瞬间就完成校验输出。正确账号:用户名 root,密码 1@3$5^7*8(0。这就是理论篇"属性 set 里可以设条件"的实战应用。
【代码】
//定义用户类
class User
{
//定义账户和密码字段
private string _name;
private string _password;
//判断用户名输入
public string Name
{
get
{
return _name;
}
set
{
if (value == "root")
{
_name = "root";
}
else
{
Console.WriteLine("登录失败");
//返回模糊错误
Console.WriteLine("用户名或者密码错误");
}
}
}
//判断密码输入
public string Password
{
get
{
return _password;
}
set
{
if (value == "1@3$5^7*8(0")
{
_password = "1@3$5^7*8(0";
Console.WriteLine("登录成功");
Console.WriteLine($"{_name},欢迎你");
}
else
{
Console.WriteLine("登录失败");
Console.WriteLine("用户名或者密码错误");
}
}
}
}
//调用
User b = new User();
Console.Write("请输入用户名:");
b.Name = Console.ReadLine();
Console.Write("请输入密码:");
b.Password = Console.ReadLine();
【运行效果】
正确登录(用户名 root、密码 1@3$5^7*8(0):
请输入用户名:root
请输入密码:1@3$5^7*8(0
登录成功
root,欢迎你
密码错误(用户名 root、密码 123456):
请输入用户名:root
请输入密码:123456
登录失败
用户名或者密码错误
【修炼要点】 set 里 value 就是赋值传进来的值,if (value == "root") 就是"输入的是不是 root"。这里有个隐藏隐患:用户名错误时 _name 没被赋值,若此时密码反而输对了,程序会先报"登录失败",随后又输出"登录成功"和一句没有名字的欢迎语(实测输出 登录成功、,欢迎你)。真正严谨的写法应该让"用户名错误"直接拦住后续校验——峰主说过,属性 set 里可以加条件,也可以直接"拦截",这正是封装的本意。
基础题三:交换两个 int 变量
【题目要求】 使用方法交换两个 int 类型的变量。
【修炼思路】 建一个 IntExchange 类,写 IE(int a, int b) 方法,用经典三行交换法(temp 暂存 → a 换 b → b 换 temp),交换后把结果打印出来。注意观察运行效果里的玄机——见修炼要点。
【代码】
//定义类
class IntExchange
{
//方法
public int IE(int a, int b)
{
int temp = a;
a = b;
b = temp;
Console.WriteLine($"{a}\\n{b}");
return –1;
}
}
//实例化
IntExchange a = new IntExchange();
int one = 23;
int two = 30;
a.IE(one, two);
【运行效果】
30
23
【修炼要点】 方法内部确实把 a、b 交换了(输出 30 和 23),但注意——实参 one、two 本身没有被改变,调用结束后 one 仍是 23、two 仍是 30。这就是 C# 的值传递:方法拿到的是值的"复印件",改复印件不影响原件。想真正交换外面的变量,得靠引用类型参数或后续学的 ref/数组,这是本题最大的坑,也是日后最容易踩的雷。
基础题四:任意长度数组求和
【题目要求】 求任意长度数组的和(整型数组)。
【修炼思路】 建一个 Arrsum 类,写 Asum(int[] a) 方法,用 for 循环遍历数组,把每个元素累加到 sum,最后 return。参数直接传数组——这是方法形参的新玩法:形参可以是一个数组变量。
【代码】
//定义类
class Arrsum
{
public int Asum(int[] a)
{
int sum = 0;
//遍历累加
for (int i = 0; i < a.Length; i++)
{
sum += a[i];
}
return sum;
}
}
//实例化
Arrsum a = new Arrsum();
int[] arr = new int[10] { 3, 4, 2, 5, 6, 7, 1, 7, 6, 7 };
Console.WriteLine(a.Asum(arr));
【运行效果】
48
(3+4+2+5+6+7+1+7+6+7 = 48,实跑验证无误。)
【修炼要点】 int[] a 作为形参,实参传一个数组进来,方法里 a.Length 拿到数组长度,a[i] 逐个取元素。不管数组多长都能求——这就是"任意长度"的含义,也是"方法封装"带来的复用价值:以后所有数组求和,一行 a.Asum(arr) 搞定。
基础题五:重载求最大值
【题目要求】 创建方法求两个数的最大值,两个数可以是整数、小数或字符,要求使用重载。
【修炼思路】 建一个 Sum 类,写三个同名 ZSum 方法:整型版返回 int、小数版返回 double、字符版返回 char,参数列表各不相同——这就是理论篇的方法重载。调用时传整数走整型版、传小数走小数版、传字符走字符版,编译器自动匹配。
【代码】
class Sum
{
//方法 整型
public int ZSum(int a, int b)
{
if (a >= b)
{
return a;
}
else
{
return b;
}
}
//方法重载,小数
public double ZSum(double a, double b)
{
if (a >= b)
{
return a;
}
else
{
return b;
}
}
//方法重载,字符
public char ZSum(char a, char b)
{
if (a >= b)
{
return a;
}
else
{
return b;
}
}
}
Sum a = new Sum();
Console.WriteLine(a.ZSum(35, 67));
Console.WriteLine(a.ZSum(3.5, 6.7));
Console.WriteLine(a.ZSum('a', 'A'));
【运行效果】
67
6.7
a
【修炼要点】 三个方法名都叫 ZSum,参数列表分别是 (int,int)、(double,double)、(char,char)——方法名一致 + 参数列表不同 = 重载。ZSum(35, 67) 走整型版返回 67;ZSum(3.5, 6.7) 走小数版返回 6.7;ZSum('a', 'A') 走字符版返回 a——字符比较的是 Unicode 码值,小写 a(97)比大写 A(65)大。字符类型用单引号,和字符串的双引号要分清。
基础题六:EAN-13 / UPC-A 零售商品条码校验
【题目要求】 13 位(或 12 位)数字,最后一位是校验位。以 EAN-13 为例:从右往左(不含校验位)交替乘以权重 1、3,加权求和后取 S mod 10,(10 – S mod 10) mod 10 得到校验位;总和加上校验位后必须是 10 的倍数才合法。
【修炼思路】 建一个 Ean 类,写 Jqqh(int[] a)(加权求和)方法:遍历数组前 12 位,偶数位(按本实现口径,即从左数第 2、4、6……位)乘以 3,累加后再加上校验位本身,返回总和;Main 里判断总和能否被 10 整除,输出"合法 / 不合法"。这和理论篇身份证校验的"加权求和"是同门功法。
【代码】
class Ean
{
//加权求和
public int Jqqh(int[] a)
{
int sum = 0;
for (int i = 0; i < a.Length – 1; i++)
{
//判断偶数位
if ((i + 1) % 2 == 0)
{
a[i] *= 3;
}
sum += a[i];
}
return sum + a[a.Length – 1];
}
}
Ean a = new Ean();
int[] arr = new int[13] { 6, 9, 2, 5, 3, 0, 3, 7, 0, 1, 7, 5, 8 };
int number = a.Jqqh(arr);
if (number % 10 == 0)
{
Console.WriteLine("合法");
}
else
{
Console.WriteLine("不合法");
}
【运行效果】
加权求和 = 110
合法
(实测:6 + 9×3 + 2 + 5×3 + 3 + 0×3 + 3 + 7×3 + 0 + 1×3 + 7 + 5×3 + 8 = 110,110 % 10 == 0 → 合法。)
【修炼要点】 这是"加权求和 + 取模判断"的典型应用,和身份证校验同宗同源。两个细节要留心:其一,本代码按"从左数偶数位 ×3"实现((i+1) % 2 == 0 时 a[i] *= 3),而题目说明的 EAN-13 标准口径是"从右往左数(校验位不算,第 2、4、6……位 ×3)"——两种口径对同一串数字结果可能不同,运行以本代码实际输出为准;其二,a[i] *= 3 会直接修改原数组,和理论篇排序的副作用一样,要心里有数。
走火入魔预警
| 闰年条件写错优先级 | `year % 4 == 0 | |
| 交换方法"看似生效" | 以为 a.IE(one, two) 后 one、two 已互换 | 值传递只交换方法内副本,实参不变;要改外部变量需引用/数组/ref |
| 用户名错误还继续走密码 | 用户名错了 _name 没赋值,密码对时输出"登录成功,欢迎你"缺名字 | 用户名错误应直接拦截,不进入密码校验 |
| 字符当字符串用 | a.Gender = "男" 报错(本日 'a'、'A' 同理) | char 用单引号,string 用双引号 |
| 重载版次乱写 | 两个方法参数列表相同还叫重载 | 同名 + 参数列表不同(数量/类型不同) |
| 加权求和方向搞混 | 标准"从右往左"与实现"从左偶数位"混用 | 明确本代码口径,以运行输出为准 |
| 加权时改了原数组 | a[i] *= 3 后数组值被污染,后续复用出错 | 需要保留原值时另开数组存储 |
今日修炼总结
六道作业题走下来,方法的全套用法已过一遍:
- 有参有返回值:题 1 判断闰年、题 4 数组求和、题 5 重载取最大值、题 6 条码校验——传参进去,返回结果;
- 属性 set 做判断:题 2 登录校验,把拦截逻辑写进属性赋值的一瞬间;
- 值传递的坑:题 3 交换方法内有效、实参不动——这是今日最值得记的教训;
- 重载实战:题 5 同一方法名三版(int/double/char)自动匹配,正是理论篇重载的作业版;
- 加权求和:题 6 与理论篇身份证校验同源,条码、身份证一法通吃。
峰主说今天作业"不难但极考细心":重载参数列表、值传递、字符单引号、加权方向,哪一处走神都会编译报错或结果跑偏。功法皆已实测跑通——六题输出 平年 / 登录成功 / 30 23 / 48 / 67 6.7 a / 110 合法,全部真实可复现。为明日方法进阶(静态、属性、构造函数继续深化)打下地基。
下一关,我们继续。
(本文为个人修炼记录,功法均可在 .NET 控制台应用下编译运行通过。如有谬误欢迎指正,一同精进。)
网硕互联帮助中心




评论前必须登录!
注册