本部分将系统性地介绍 C# 编程语言,帮助读者从零基础逐步掌握其基本用法与核心概念。课程内容涵盖开发环境的搭建、首个项目的创建、基础语法的讲解及典型用例示范。 无论有无编程经验,你都可以通过循序渐进的学习,理解每个关键点,真正掌握 C# 项目开发的流程与方法。

先说几个关键词:现代、强类型、面向对象、跨平台。C# 由微软设计,和 .NET 平台一起工作。今天的 C# 可以在 Windows、macOS、Linux 上运行; 可以写控制台程序、桌面软件、Web 后端、小游戏,甚至移动应用(Xamarin/Maui)。
你会经常看到两个名字:C# 和 .NET。简单理解:C# 是语言,就像“中文”; .NET 是运行时和标准库,就像“字典+工具箱”。我们用 C# 说话,用 .NET 提供的工具去做事。
要写 C#,我们需要两个东西:
安装完成后,打开终端(Windows 上可以用 PowerShell),输入:
|dotnet --version
如果能看到一个版本号,比如 8.x 或 7.x,说明 .NET 安装成功。
接着,我们来创建第一个控制台项目。选择一个空文件夹,在终端执行:
|dotnet new console -n HelloCSharp cd HelloCSharp dotnet run
你应该会看到屏幕上打印出:
Hello, World!我们已经把“第一个音”发出来了。下面,我们不急着往下跑,先把这个小小的“Hello, World!”拆开看看。
创建出来的项目里,有一个文件 Program.cs。它的内容大概是这样(不同版本模板略有差别):
|// Program.cs using System; // 引入 System 命名空间(提供控制台、基础类型等常用功能) // 这是主程序入口点。对顶级语句模板而言,编译器会为我们生成 Main 方法。 Console.WriteLine("Hello, World!"); // 输出一行文本到控制台
如果你看到的是带 namespace 和 class Program 的版本,也没关系,原理一样。新模板为了简洁,省略了那些“礼仪性的开场白”,让我们可以专注在核心逻辑上。
我们后面会讲“命名空间”“类”和“Main 方法”到底是什么。先记住两点:
第一,Console.WriteLine(...) 是输出一行文字;第二,代码一行行从上往下执行,遇到输出就把内容打印到屏幕上。
很多书一上来就把“程序结构”讲得很复杂,我们只抓关键:
using System; 就是在说:我要用 System 里的东西。Main。顶级语句模板把它藏起来了,但它仍然存在。为了让你看到“完整版”,我们写一个带 Main 的最小示例:
|// Program.cs(显式 Main 版本) using System; // 引入基础工具箱 namespace GettingStarted // 命名空间,像文件夹名 { internal class Program // 定义一个类 Program,internal 先不用纠结 { // Main 是程序入口。string[] args 是命令行参数(暂时不用) static void Main(string[] args) { Console.WriteLine("你好,C# 的世界!"); } } }
逐行理解:我们先搬进 System 工具箱,然后声明一个命名空间 GettingStarted,里面放一个 Program 类。类里有一个 Main 方法,程序从这里开始,执行输出语句,结束。
程序和现实一样,需要“记住东西”。变量就是“带名字的盒子”,数据类型规定了盒子里能放什么:整数、浮点数、文本、真假等等。
常见基础类型:
int(32位整数)、long(更大)double(常用浮点)、float(更小精度)、decimal(高精度常用于金额)string(字符串)、char(单个字符)bool(true 或 false)我们写一个小程序:记录今天学习的时长,然后打印出来。
|// 变量示例:study-time.cs using System; class StudyTimeDemo { static void Main() { // 声明一个整型变量,表示今天学习了多少小时 int hours = 2; // 我们先赋值 2,后面可以改 // 声明一个浮点型变量,记录分钟(小数) double minutes = 30.5; // 30.5 分钟 // 声明一个字符串变量,记录学习主题 string topic = "C# 入门"; // 声明一个布尔变量,记录今天是否达成目标 bool
运行后你会看到相应的输出。注意 + 在拼接字符串时的作用:把多个片段连成一段文本。也可以用插值字符串的写法,更优雅:
|Console.WriteLine($"今天学习主题: {topic}");
插值字符串里,花括号 {} 就像“窗口”,可以把变量的值展示出来。
变量名请用有意义的英文或拼音英文化,推荐使用小驼峰:studyHours、targetReached。我们要写给“未来的自己”和“团队伙伴”看,越清晰越好。
有时候需要把一种类型变成另一种,比如把字符串变成整数,或者让整数参与小数计算。最常见的是这几种方式:
|int a = 5; double b = a; // 隐式转换:int 可以自动转 double double c = 3.14; int d = (int)c; // 显式转换(强制类型转换):小数到整数需要手动,可能丢失小数部分 string s = "123"; int num = int.Parse(s); // 解析字符串为整数(若 s 非法会抛异常) // 更安全:TryParse,不抛异常,用返回值表示是否成功 bool ok =
TryParse 像是“温柔型转换器”,失败也不生气,返回 false,并把输出变量设为默认值。
Console.WriteLine 是“我们说话”;Console.ReadLine 是“我们倾听”。我们做一个小例子:计算 BMI(体质指数),并且把每一步解释清楚。
|// bmi.cs using System; class BmiCalculator { static void Main() { // 提示并读取身高(米) Console.Write("请输入你的身高(米): "); string? heightInput = Console.ReadLine(); // 可能为 null,用 ? 表示可空 // 提示并读取体重(千克) Console.Write("请输入你的体重(kg): "); string? weightInput = Console.
这个程序用到了输入、解析、条件判断、格式化输出。我们也见识了“早返回”的写法:当输入不对,直接 return,让代码更干净。
C# 提供了丰富的运算符来处理数据和逻辑:
算术运算符:
+(加法)、-(减法)、*(乘法)、/(除法)、%(取余)5 / 2 结果是 2,而 5.0 / 2 结果是 2.5n % 2 == 0 表示偶数比较运算符:
==(等于)、!=(不等于)<(小于)、<=(小于等于)、>(大于)、>=(大于等于)bool 类型的结果逻辑运算符:
&&(逻辑与,短路求值)、||(逻辑或,短路求值)、!(逻辑非)a && b 当 a 为 false 时不会计算 b;a || b 当 a 为 true 时不会计算 b运算符优先级:算术 > 比较 > 逻辑,但复杂表达式建议用括号明确意图,让代码更易读。比如 (age >= 18) && (score > 60) 比 age >= 18 && score > 60 更清晰。
我们写一个“目标检查器”:
|// goal-checker.cs using System; class GoalChecker { static void Main() { int dailyTarget = 60; // 每天目标学习 60 分钟 Console.Write("请输入今天学习分钟数: "); string? input = Console.ReadLine(); bool ok = int.TryParse(input, out
注意三元表达式 条件 ? 值1 : 值2。虽然方便,但不要滥用,复杂情况用 if/else 更清晰。
程序需要根据不同情况做出不同的行为,这就是"分支控制"。就像我们在现实生活中做决定一样:如果天气晴朗就去公园,如果下雨就在家看书。
在 C# 中,最常用的分支结构是 if/else,它让程序能够"看情况行事"。当我们需要处理多个条件时,switch 语句(特别是 C# 8+ 的 switch 表达式)能让代码更加简洁清晰。
下面我们写一个成绩评级器,同时演示 if/else 和 switch 两种写法的区别:
|// grade.cs using System; class GradeClassifier { static void Main() { Console.Write("请输入成绩(0-100): "); string? input = Console.ReadLine(); // 检查输入是否合法 if (!int.TryParse(input, out int score) || score <
switch 表达式常常让代码更紧凑。记住:清晰第一,紧凑第二。
当我们需要重复做某件事,编程语言提供了四种主要的循环方式:
我们通过一个"猜数字游戏"来实际体验这几种循环。这个游戏的规则是:程序想一个数字,用户有限次机会猜,每次猜错会提示"大了"或"小了",猜对了就胜利。
|// guess.cs using System; class GuessNumber { static void Main() { // 目标数字(真实项目里我们会用随机数,这里为了讲解固定为 42) int secret = 42; // 最多尝试 5 次 int maxTries = 5; // for 循环控制次数 for (int attempt = 1; attempt <= maxTries; attempt++)
循环的关键是“循环条件”和“更新状态”。当你调试循环问题时,多打印变量,像打手电筒一样照亮黑箱。
数组就像是固定座位数的教室——你提前订好 10 个位置,就只能坐 10 个人,不能临时加椅子。声明时必须指定长度:int[] scores = new int[5];,这就预留了 5 个整数的空间。
相比之下,List<T> 更像是可以随时扩容的自助餐厅——开始可能只摆 3 张桌子,人多了就加桌子,人少了也能收起来。我们可以用 Add() 添加元素,用 Remove() 删除元素,用 Count 属性查看当前有多少项。
两者各有适用场景:如果你明确知道要存储的数据个数(比如一周 7 天的气温),数组足够简单高效;如果数据量会动态变化(比如用户逐个输入的购物清单),List<T> 更灵活方便。
下面我们用它们做一个小型"成绩统计器",看看实际使用中的差别:
|// scores.cs using System; using System.Collections.Generic; // 使用 List 所需的命名空间 class ScoreStats { static void Main() { // 用数组存三次测验的成绩 int[] exams = new int[3]; exams[0] = 85; exams[1]
我们刚才见到了"方法重载"的实际应用:两个同名的 Average 方法,但参数类型不同——一个接受 int[] 数组,另一个接受 List<int> 列表。
这是 C# 的一个强大特性,让我们能用同一个方法名表达相同的逻辑概念,而编译器会根据我们传入的参数类型自动选择合适的版本。
想象一下,如果没有方法重载,我们可能需要写成 AverageArray() 和 AverageList() 这样的名字。
但"求平均数"本质上是同一个动作,不管容器是什么类型。方法重载让代码更简洁、更符合人类思维:我们说"计算平均值",系统自动判断用哪种实现方式。
注释是给“未来的我们”看的。好的注释解释“为什么”,而不是“怎么写”。
// 标注关键意图。示例:
|// 计算应付款:在原价基础上应用折扣,然后加上税费 static decimal CalculatePayable(decimal price, decimal discountRate, decimal taxRate) { decimal discounted = price * (1 - discountRate); decimal taxed = discounted * (1 + taxRate); return taxed; }
即便没有中文注释,也能从命名看出意图。这就是“写给未来的我们”。
当你 dotnet new console 时,会生成一个 .csproj 文件。它记录了项目名称、目标框架、依赖等信息。一个典型的控制台项目结构:
|HelloCSharp/ HelloCSharp.csproj Program.cs
常用命令:
|dotnet restore # 还原依赖(首次/变更依赖时) dotnet build # 构建项目(编译) dotnet run # 运行(会自动构建) dotnet publish # 发布可部署的产物
9. 温度转换器练习
编写一个温度转换程序,实现以下功能:
Console.Write() 或 Console.WriteLine() 提示用户输入摄氏度Console.ReadLine() 读取用户输入的字符串double.Parse() 或 Convert.ToDouble() 将字符串转换为浮点数F = C × 9/5 + 32 计算华氏度Console.WriteLine() 输出结果,格式为 $"{fahrenheit:F1}°F",保留1位小数try-catch 处理(可选)|using System; class TemperatureConverter { static void Main() { Console.Write("请输入摄氏度: "); string input = Console.ReadLine(); double celsius = double.Parse(input); double fahrenheit = celsius * 9.0 / 5.0
10. 倒计时器练习
编写一个倒计时程序,实现以下功能:
Console.Write() 提示用户输入倒计时的秒数Console.ReadLine() 读取用户输入的字符串int.Parse() 或 Convert.ToInt32() 将字符串转换为整数while 循环,从输入的秒数开始倒数到1Console.WriteLine())Thread.Sleep(1000) 让程序暂停1秒(需要 using System.Threading;)try-catch 处理(可选)|using System; using System.Threading; class CountdownTimer { static void Main() { Console.Write("请输入倒计时秒数: "); string input = Console.ReadLine(); int seconds = int.Parse(input); while
11. 打卡提醒练习
编写一个学习打卡程序,实现以下功能:
List<(string topic, int minutes)> 来存储学习记录Console.Write() 和 Console.ReadLine())Console.Write() 和 Console.ReadLine())Add() 方法)OrderByDescending() 方法按分钟数从大到小排序foreach 循环遍历排序后的列表,打印每条记录using System.Linq; 来使用 OrderByDescending() 方法|using System; using System.Collections.Generic; using System.Linq; class StudyTracker { static void Main() { List<(string topic, int minutes)> records = new List<(string, int)>();
|请输入摄氏度: 25 77.0°F
说明:
Console.Write() 输出提示信息,不换行Console.ReadLine() 读取用户输入的一行文本double.Parse() 将字符串转换为浮点数9.0 / 5.0 使用浮点数除法,避免整数除法{fahrenheit:F1} 格式化输出,保留1位小数|请输入倒计时秒数: 5 5 4 3 2 1 时间到
说明:
while 循环先判断条件,再执行循环体Thread.Sleep(1000) 让程序暂停1000毫秒(1秒)seconds-- 递减操作,每次循环减少1seconds > 0 确保倒数到1后停止|请输入学习主题: C#基础 请输入学习分钟数: 60 是否继续输入?(y/n): y 请输入学习主题: 算法练习 请输入学习分钟数: 45 是否继续输入?(y/n): y 请输入学习主题: 项目实践 请输入学习分钟数: 90 是否继续输入?(y/n): n 学习记录(按分钟数从大到小): 项目实践: 90 分钟 C#基础: 60 分钟 算法练习: 45 分钟
说明:
List<(string, int)> 使用元组语法,存储主题和分钟数while (true) 创建无限循环,通过 break 退出OrderByDescending() 按指定字段降序排序foreach 遍历排序后的集合record.topic 和 record.minutesusing System.Linq; 来使用 LINQ 方法