1. 从控制台到窗口:为什么选择WinForm来练习C#
很多朋友刚开始学C#的时候,都是从控制台应用(Console Application)入手的。黑底白字的命令行窗口,Console.WriteLine 打印出一行行结果,确实能让我们把注意力集中在语法和逻辑上。我刚开始学那会儿,也是这么过来的,觉得能写出一个能跑起来的计算器就挺有成就感。但时间一长,难免会觉得有点枯燥,毕竟我们日常用的软件,无论是QQ、微信还是各种办公工具,都是一个个有按钮、有输入框、有菜单的窗口程序。
这时候,WinForm就该登场了。你可以把它理解成是微软给我们准备好的一套“乐高积木”。我们想做一个有界面的程序,不需要从零开始去画窗口、处理鼠标点击这些底层又繁琐的事情。WinForm已经把这些最基础的“积木块”——比如按钮(Button)、文本框(TextBox)、标签(Label)、列表框(ListBox)——都做好了,我们只需要把这些“积木”拖到设计界面上,摆好位置,然后告诉它们:“当你被点击的时候,去执行我写的这段代码”。这种“所见即所得”的开发方式,对于新手来说,上手速度极快,成就感也来得特别直接。
更重要的是,通过WinForm来练习C#,尤其是面向对象和类继承这些概念,效果会好得多。为什么?因为WinForm本身就是一个巨大的、活生生的面向对象案例。你看到的每一个窗体(Form),本身就是一个类。你拖上去的每一个按钮,也都是一个类的实例。当你双击按钮,为它的Click事件编写代码时,你其实就是在和这个按钮对象“对话”。这种直观的对应关系,比单纯在控制台里定义几个抽象的“学生类”、“老师类”要生动得多。你能立刻看到你的代码是如何驱动界面元素、如何响应用户操作的,这种即时反馈对学习编程来说,是无价之宝。
所以,这套实战题集的设计思路,就是从最基础的控制台输入输出开始,让你先熟悉C#的语法和基本数据结构。等你对变量、循环、数组这些有了手感之后,我们再平滑地过渡到WinForm的世界。你会看到,同样的逻辑(比如找最大值、处理数组),在WinForm里是如何通过按钮点击来触发,结果又是如何显示在文本框或者列表里的。最后,我们再深入到面向对象的核心——类继承,用图形化的例子来理解“父类”和“子类”的关系。整个过程就像爬楼梯,一步一个台阶,既巩固了基础,又逐步接触了更实用、更有趣的GUI开发。
2. 夯实基础:五个必做的控制台编程题
在接触华丽的窗口界面之前,我们必须把内功练扎实。下面这五个控制台练习题,是我当年学习时觉得非常经典的“敲门砖”,它们覆盖了数据处理、逻辑判断和基本算法,能帮你快速建立对C#的“手感”。
2.1 实战一:从一行数字中找出“老大”
这个题目要求我们接收用户输入的一串用空格隔开的整数,然后找出其中的最大值。听起来简单,但它完美地串联了字符串处理、数组转换和循环比较这几个核心技能点。
我刚开始做这个题时,犯过一个典型的错误:试图用一个复杂的for循环,边分割字符串边比较。结果代码写得又乱又容易出错。后来才明白,处理这类问题,最好的办法就是“分而治之”。第一步,用Console.ReadLine()拿到用户输入的整行字符串。第二步,调用Split(' ')方法,以空格为分隔符,把这串字符“切”成一个字符串数组。这一步就像把一串葡萄摘成一粒一粒的。第三步,才是遍历这个字符串数组,把每个“字符串葡萄”用Convert.ToInt32()转换成“整数葡萄”,同时用一个max变量当“擂台主”,不断和新的数字比武,打赢了就留在台上。
这里有个小技巧,初始化max变量时,不要设成0。万一用户输入的全是负数,0反而成了最大值,那就闹笑话了。正确的做法是把它初始化为int.MinValue,这是整数类型能表示的最小值,保证任何输入的第一个数都能“打败”它,顺利成为第一个擂主。
static void FindMaxNumber()
{
Console.Write("请输入一串整数,用空格分隔:");
string input = Console.ReadLine();
string[] numberStrings = input.Split(' ');
int max = int.MinValue; // 安全的初始值
foreach (string numStr in numberStrings)
{
int currentNumber = Convert.ToInt32(numStr);
if (currentNumber > max)
{
max = currentNumber;
}
}
Console.WriteLine($"最大的数是:{max}");
}
2.2 实战二:给任意秒数穿上“时分秒”的外衣
这个题目是单位换算的经典应用。给你一个总秒数,比如3665秒,让你换算成“1小时1分钟5秒”这样的格式。它考察的是整数除法和取余运算的灵活运用。
我的思路是这样的:既然1小时是3600秒,那么用总秒数除以3600,得到的整数商就是小时数。然后,用总秒数减去“小时数*3600”,剩下的就是不够1小时的零头秒数。再用这个零头除以60,商就是分钟数,最后的余数就是秒数。这个“除大取整,减余再除”的过程,是处理这类复合单位换算的通用方法。
在实际写代码时,我建议你特别注意输出格式。题目要求,如果没有分钟,就只显示“X小时Y秒”。这需要我们在输出前加一个判断。我见过有新手朋友用一堆if-else来拼接字符串,其实用C#的字符串插值($)或者string.Format配合条件判断,一行代码就能优雅地搞定。
static void ConvertSeconds()
{
Console.Write("请输入总秒数:");
int totalSeconds = Convert.ToInt32(Console.ReadLine());
int hours = totalSeconds / 3600;
int remainingSeconds = totalSeconds % 3600;
int minutes = remainingSeconds / 60;
int seconds = remainingSeconds % 60;
// 灵活处理输出,避免出现“0小时1分钟5秒”这样的冗余信息
string output = "";
if (hours > 0) output += $"{hours}小时";
if (minutes > 0) output += $"{minutes}分";
if (seconds > 0 || output == "") output += $"{seconds}秒"; // 保证至少输出一个单位
Console.WriteLine(output);
}
2.3 实战三:模拟一座“任性”的电梯
这个题目非常有趣,它模拟了一个不按常理出牌的电梯:它只按照你输入楼层序列的顺序运行,而且运行完就停在那层,不回一楼。我们需要计算完成整个序列的运行时间。这题的关键在于状态记录和条件判断。
电梯的“状态”就是它当前所在的楼层。我们需要一个变量(比如currentFloor)来记住它。每次接到一个新指令(下一个目标楼层),我们就要计算从currentFloor到新楼层的距离。这里要注意,上楼和下楼的速度不同,题目给了上楼每层6秒,下楼每层4秒。所以,如果新楼层 > currentFloor,就是上楼,时间加“层差6”;反之则加“层差4”。
还有一个容易忽略的细节:停留时间。题目说“在某层停留,无论上下人多少,均停留5秒”。那什么算“停留”呢?并不是每层都停,而是当目标楼层与当前楼层不同时才需要停。如果用户连续输入两个相同的楼层(比如从2楼又按了2楼),电梯其实没动,自然也就不存在“停留”一说。所以,在计算时间前,要先判断新楼层 != currentFloor,如果成立,先加上5秒的停留时间,再计算移动时间。
static void CalculateElevatorTime()
{
int currentFloor = 0; // 电梯从0层开始
int totalTime = 0;
Console.WriteLine("请输入楼层序列(以0结束):");
string input = Console.ReadLine();
string[] floors = input.Split(' ');
foreach (string floorStr in floors




48

被折叠的 条评论
为什么被折叠?



