一、前言
上一篇我们搭建好了开发环境,这一篇我们来学习 C# 的基础语法。
C# 是一门非常优雅的编程语言,语法清晰,功能强大。别担心,我会用最简单的方式来讲解,保证你能看懂。
1.1、什么是变量?
变量就像是一个"盒子",用来存放数据。你可以给盒子起个名字,然后往里面放东西。
csharp
// 声明一个变量,存放年龄
int age = 25;
// 声明一个变量,存放名字
string name = "张三";
// 声明一个变量,存放价格
double price = 99.9;
这段代码展示了如何声明和使用变量。int 是整数类型,用于存储没有小数部分的数字。string 是字符串类型,用于存储文本。double 是浮点类型,用于存储带小数点的数字。等号是赋值操作符,把右边的值赋给左边的变量。每个语句最后加分号,表示这行代码结束。
1.2、常用数据类型
C# 提供了多种数据类型,用来存储不同种类的数据。
整数类型用于存储整数,有 int、long、short 等不同大小。int 最常用,范围大约是 -21 亿到 21 亿,对于大多数场景够用了。long 范围更大,可以存储更大的整数。short 范围较小,节省内存。
浮点类型用于存储带小数点的数字。double 是双精度浮点数,精度高,范围大。float 是单精度浮点数,精度稍低,占用内存少。decimal 是精确小数类型,特别适合存储金额等需要精确计算的场景。
布尔类型用于存储真或假,只有两个值,true 和 false。bool 通常用于条件判断的结果。比如判断一个数字是否大于零,结果就是 bool 类型。
字符串类型用于存储文本。可以存储单个字符、一段话、一篇文章等。string 是引用类型,可以存储任意长度的文本。字符串有很多方法,比如获取长度、查找子串、替换字符等,用起来很方便。
1.3、var 关键字
如果你懒得写类型,可以用 var,编译器会自动推断。
csharp
var age = 25; // 自动推断为 int
var name = "张三"; // 自动推断为 string
var price = 99.9; // 自动推断为 double
var isStudent = true; // 自动推断为 bool
这段代码使用 var 关键字声明变量,编译器会根据赋值的表达式自动推断变量类型。age 赋值为 25,是整数,所以推断为 int。name 赋值为字符串字面量,推断为 string。price 赋值为浮点数字面量,推断为 double。isStudent 赋值为 true,推断为 bool。
var 只是让你少写代码,变量的类型在编译时就确定了,不是动态类型。这意味着你不能给一个 var 变量先赋整数,然后赋字符串,因为类型不匹配。不过在同一行用 var 声明多个变量时,它们的类型必须相同。
注意 var 不能用于字段声明,只能在局部变量中使用。而且 var 必须初始化,因为编译器需要根据初始值推断类型。如果你只是想声明一个变量而不初始化,就不能用 var。
二、运算符
C# 提供了各种运算符,用于进行计算和比较。
2.1、算术运算符
算术运算符用于数学计算,加减乘除这些基本运算。
csharp
int a = 10;
int b = 3;
int sum = a + b; // 加法:13
int diff = a - b; // 减法:7
int product = a * b; // 乘法:30
int quotient = a / b; // 除法:3(整数除法)
int remainder = a % b; // 取余:1
加法运算符 + 把两个数加起来。减法运算符 - 从第一个数中减去第二个数。乘法运算符 * 计算两个数的积。除法运算符 / 用第一个数除以第二个数。取余运算符 % 计算第一个数除以第二个数的余数。
注意整数除法会丢弃小数部分。比如 10 除以 3,结果是 3,不是 3.333。如果需要浮点数结果,要用 double 类型。
csharp
double x = 10.0;
double y = 3.0;
double result = x / y; // 结果是 3.333...
这段代码用 double 类型进行除法,结果是浮点数。x 除以 y 得到 3.333...,保留了小数部分。如果你想控制小数位数,可以使用格式化字符串。
2.2、比较运算符
比较运算符用于比较两个值,返回结果是 true 或 false。
csharp
int a = 10;
int b = 20;
bool greater = a > b; // 大于:false
bool less = a < b; // 小于:true
bool equal = a == b; // 等于:false
bool notNotEqual = a != b; // 不等于:true
bool ge = a >= b; // 大于等于:false
bool le = a <= b; // 小于等于:true
大于运算符 > 判断第一个数是否大于第二个数。小于运算符 < 判断第一个数是否小于第二个数。等于运算符 == 判断两个数是否相等。不等于运算符 != 判断两个数是否不等。大于等于运算符 >= 判断第一个数是否大于或等于第二个数。小于等于运算符 <= 判断第一个数是否小于或等于第二个数。
这些运算符不仅用于数字,也可以用于字符串。字符串比较是按字典序比较的,比较的是每个字符的 Unicode 码。
csharp
string s1 = "apple";
string s2 = "banana";
bool result = s1 < s2; // true,因为 'a' 的码小于 'b'
2.3、逻辑运算符
逻辑运算符用于组合布尔值,进行逻辑运算。
csharp
bool a = true;
bool b = false;
bool and = a && b; // 逻辑与:false(两个都为真才为真)
bool or = a || b; // 逻辑或:true(一个为真就为真)
bool not = !a; // 逻辑非:false(真变假,假变真)
逻辑与运算符 && 只有当两个操作数都是 true 时,结果才为 true。如果第一个操作数是 false,就不会计算第二个操作数,这叫短路求值。逻辑或运算符 || 只要有一个操作数是 true,结果就是 true。如果第一个操作数是 true,就不会计算第二个操作数。逻辑非运算符 ! 把 true 变成 false,把 false 变成 true。
短路求值可以提高性能。比如你要判断一个对象是否不为 null 并且某个属性为 true,可以写成 obj != null && obj.IsValid。如果 obj 是 null,第二个表达式就不会执行,避免了空引用异常。
三、字符串操作
字符串是 C# 中非常重要的数据类型,用于存储和处理文本信息。
3.1、字符串拼接
字符串拼接就是把多个字符串连接成一个字符串。
csharp
string firstName = "张";
string lastName = "三";
string fullName = firstName + " " + lastName; // "张 三"
// 使用字符串插值
string greeting = $"你好,{fullName}!"; // "你好,张 三!"
加法运算符 + 可以用于拼接字符串。firstName 加上空格,再加上 lastName,得到全名。字符串插值用 $ 开头的字符串,可以在大括号中嵌入变量或表达式。
字符串插值比加法运算符更方便,特别是需要拼接多个变量时。而且字符串插值在编译时会转换成 String.Format 调用,性能更好。你可以在大括号中写任何 C# 表达式,比如方法调用、数学运算等。
csharp
int age = 25;
string message = $"明年你{age + 1}岁"; // "明年你26岁"
这段代码演示了字符串插值中可以写表达式。age + 1 是一个加法表达式,结果是 26,然后嵌入到字符串中。字符串插值会在运行时计算表达式,所以你可以动态生成内容。
3.2、字符串常用方法
字符串类型提供了很多有用的方法。
csharp
string text = "Hello, World!";
// 获取长度
int length = text.Length; // 13
// 转大写
string upper = text.ToUpper(); // "HELLO, WORLD!"
// 转小写
string lower = text.ToLower(); // "hello, world!"
// 是否包含
bool contains = text.Contains("Hello"); // true
// 替换
string replaced = text.Replace("World", "C#"); // "Hello, C#!"
// 分割
string[] parts = text.Split(','); // ["Hello", " World!"]
Length 属性返回字符串的字符数。注意不是字节数,是字符数,因为 C# 的字符串使用 Unicode 编码,一个字符可能占用多个字节。ToUpper 方法把字符串转换成大写,所有字母都变成大写。ToLower 方法把字符串转换成小写,所有字母都变成小写。
Contains 方法检查字符串是否包含指定的子字符串,返回 true 或 false。Replace 方法把字符串中的某个子字符串替换成另一个字符串。Split 方法根据指定的分隔符把字符串分割成字符串数组,返回所有部分。
csharp
string path = "/home/user/documents";
string[] components = path.Split('/');
// components = ["", "home", "user", "documents"]
string joined = string.Join("\\", components);
// joined = "\\home\\user\\documents"
这段代码演示了字符串的分割和拼接。Split('/') 用斜杠分割路径,得到各个部分。string.Join 方法把字符串数组连接成一个字符串,用指定的分隔符分开。这里用反斜杠连接,因为 Windows 路径使用反斜杠。
四、数组基础
数组用于存储多个相同类型的值。
4.1、声明数组
csharp
// 声明一个整数数组
int[] numbers = { 1, 2, 3, 4, 5 };
// 声明一个字符串数组
string[] names = { "张三", "李四", "王五" };
// 声明并指定大小
int[] scores = new int[10]; // 创建一个长度为 10 的数组,元素都初始化为 0
这段代码演示了三种声明数组的方式。第一种是用花括号初始化器,直接在声明时初始化数组元素。第二种是声明字符串数组,也用花括号初始化。第三种是用 new 关键字指定数组大小,这会创建一个指定长度的数组,所有元素都初始化为默认值。
数组的大小在创建时就确定了,之后不能改变。如果你需要一个可以动态改变大小的集合,应该用 List。数组的索引从 0 开始,所以长度为 5 的数组,最后一个元素的索引是 4。
4.2、访问数组元素
csharp
int[] numbers = { 10, 20, 30, 40, 50 };
// 访问第一个元素
int first = numbers[0]; // 10
// 访问最后一个元素
int last = numbers[4]; // 50
// 修改元素
numbers[2] = 100; // 第三个元素变成 100
// 遍历数组
foreach (int num in numbers)
{
Console.WriteLine(num);
}
用方括号访问数组元素,方括号里是索引。索引从 0 开始,所以 numbers[0] 是第一个元素,numbers[4] 是第五个元素。在 C# 8.0 及以上版本,你还可以使用 ^ 运算符进行倒数索引,例如 numbers[^1] 表示最后一个元素,numbers[^2] 表示倒数第二个元素。
修改数组元素也是用方括号,直接赋值就行。这里把第三个元素改成 100。foreach 循环遍历数组中的所有元素,依次取出每个元素。在循环体中,你可以对每个元素进行操作。
csharp
string[] names = { "张三", "李四", "王五" };
for (int i = 0; i < names.Length; i++)
{
Console.WriteLine($"第{i + 1}个:{names[i]}");
}
这段代码用 for 循环遍历数组,同时显示索引。for 循环有三个部分:初始化、条件、迭代。初始化在循环开始前执行一次,这里设置 i 为 0。条件在每次循环开始前检查,如果为 true 就继续循环。迭代在每次循环结束后执行,这里让 i 加 1。
五、条件判断
条件判断让程序能够根据不同情况执行不同的代码。
5.1、if 语句
if 语句是最基本的条件判断。
csharp
int age = 20;
if (age >= 18)
{
Console.WriteLine("你已经成年了");
}
if (age < 18)
{
Console.WriteLine("你还是未成年人");
}
if 语句检查条件,如果条件为 true 就执行大括号中的代码。这里检查 age 是否大于或等于 18,如果就输出成年信息。第二个 if 检查 age 是否小于 18,如果就输出未成年人信息。
注意 if 条件后面必须是一个布尔表达式,也就是结果为 true 或 false 的表达式。你可以使用比较运算符、逻辑运算符、变量等。
csharp
int score = 85;
if (score >= 90)
{
Console.WriteLine("优秀");
}
else if (score >= 80)
{
Console.WriteLine("良好");
}
else if (score >= 60)
{
Console.WriteLine("及格");
}
else
{
Console.WriteLine("不及格");
}
这段代码演示了多条件判断。if else if 结构会依次检查每个条件,第一个为 true 的条件的代码块会被执行,后面的都不会检查。else 表示前面的条件都不满足时的默认处理。
5.2、switch 语句
switch 语句用于多个值的匹配。
csharp
int day = 3;
switch (day)
{
case 1:
Console.WriteLine("星期一");
break;
case 2:
Console.WriteLine("星期二");
break;
case 3:
Console.WriteLine("星期三");
break;
default:
Console.WriteLine("其他");
break;
}
switch 语句根据表达式的值跳转到对应的 case。这里 day 的值是 3,所以会执行 case 3 的代码。每个 case 后面都要有 break,否则会继续执行下一个 case 的代码。default 是默认处理,当所有 case 都不匹配时执行。
switch 语句可以匹配整数、字符串、枚举等类型。但是 switch 语句的条件必须是常量表达式,不能是变量或方法调用。
csharp
string grade = "A";
switch (grade)
{
case "A":
Console.WriteLine("优秀");
break;
case "B":
Console.WriteLine("良好");
break;
case "C":
Console.WriteLine("及格");
break;
default:
Console.WriteLine("待努力");
break;
}
这段代码演示了字符串的 switch 匹配。grade 的值是 "A",所以会执行第一个 case 的代码。字符串比较是区分大小写的,所以 "a" 和 "A" 是不同的。如果你希望不区分大小写,可以先把字符串转换成大写或小写再比较。
六、循环
循环让程序能够重复执行某段代码。
6.1、for 循环
for 循环是最常用的循环之一。
csharp
// 打印 1 到 10
for (int i = 1; i <= 10; i++)
{
Console.WriteLine(i);
}
// 计算阶乘数
int n = 5;
int factorial = 1;
for (int i = 1; i <= n; i++)
{
factorial *= i;
}
Console.WriteLine($"{n}的阶乘是{factorial}"); // 5的阶乘是120
for 循环有三个部分:初始化、条件、迭代。初始化在循环开始前执行一次,这里设置 i 为 1。条件在每次循环开始前检查,如果为 true 就继续循环。迭代在每次循环结束后执行,这里让 i 加 1。所以这个循环会执行 10 次,i 的值分别是 1 到 10。
第二个示例计算阶乘数。factorial 初始化为 1,然后在循环中不断乘以 i。1 乘以 1 等于 1,2 乘以 1 等于 2,3 乘以 2 等于 6,依此类推。最后 factorial 的值是 120,也就是 5 的阶乘。
6.2、while 循环
while 循环在条件为 true 时持续执行。
csharp
int count = 0;
while (count < 5)
{
Console.WriteLine($"当前计数:{count}");
count++;
}
Console.WriteLine("循环结束");
while 循环在每次循环开始前检查条件。如果条件为 true,就执行循环体。这个循环会检查 count 是否小于 5,如果是就执行循环体。循环体中先打印当前计数,然后把 count 加 1。
当 count 变成 5 时,条件 count < 5 变成 false,循环结束。所以这个循环会执行 5 次,count 的值分别是 0 到 4。循环结束后打印"循环结束"。
6.3、foreach 循环
foreach 循环用于遍历集合。
csharp
string[] fruits = { "苹果", "香蕉", "橙子" };
foreach (string fruit in fruits)
{
Console.WriteLine($"我喜欢{fruit}");
}
foreach 循环遍历数组或集合中的每个元素。fruits 是一个字符串数组,foreach 循环会依次取出每个元素赋值给 fruit 变量,然后执行循环体。所以这个循环会执行 3 次,依次打印每个水果。
foreach 循环不需要你关心索引,直接处理元素。这比 for 循环更简洁,特别是在你不需要索引的时候。但是 foreach 循环不能修改集合,如果你想添加或删除元素,要用 for 循环或者把元素复制到一个新集合。
csharp
List<int> numbers = new List<int> { 1, 2, 3, 4, 5 };
foreach (int num in numbers)
{
Console.WriteLine(num * 2);
}
numbers.Add(6); // foreach 循环外可以修改
这段代码演示了 foreach 循环的使用。numbers 是一个整数列表,foreach 循环遍历每个元素并打印它的两倍。foreach 循环结束后,我们仍然可以修改列表,这里添加了元素 6。
七、总结
这篇文章我们学习了 C# 的基础语法。包括变量和数据类型,了解了如何声明和使用各种类型的变量。学习了运算符,包括算术运算符、比较运算符和逻辑运算符。学习了字符串操作,包括字符串拼接、字符串方法。学习了数组基础,包括声明数组和访问数组元素。学习了条件判断,包括 if 语句和 switch 语句。学习了循环,包括 for 循环、while 循环和 foreach 循环。
这些是编程的基础,掌握了它们,你就能写出很多有用的程序了。
八、下一篇预告
下一篇文章我们将学习面向对象编程的基础,包括类、对象、属性、方法等。面向对象是 C# 的核心特性,是现代编程的重要思想。通过学习面向对象,你将能够设计出结构清晰、易于维护的代码,写出更加专业和优雅的程序。
练习题:
- 编写一个程序,计算 1 到 100 之间所有偶数的和
- 创建一个字符串数组,存储你喜欢的电影名称,然后遍历输出
- 编写一个程序,判断一个年份是否是闰年(能被4整除但不能被100整除,或者能被400整除)
- 使用字符串方法,将一个句子中的所有单词首字母转换为大写
- 创建一个整数数组,找出其中的最大值和最小值