上一次,我们成功让电脑对世界说了声 Hello。但在实际开发中,程序主要是在处理数据——用户的名字、游戏的分数、商品的价格。
要处理数据,首先得给数据找个“容器”存起来,这就是变量 (Variable) 。
在 C# 中,创建一个变量的公式是:数据类型 变量名 = 初始值;
int age = 18; // 整数string name = "Pipi"; // 字符串bool isCool = true; // 布尔值(是/否)double price = 99.9; // 小数你可以把变量想象成一个盒子:
int :这个盒子是专门装整数的,形状固定。name :是贴在盒子上的标签,方便你找到它。18 :是盒子里装的具体东西。💡 偷懒小技巧:神奇的 var如果你觉得每次都要写类型太麻烦,C# 提供了 var 关键字(类型推断)。
var age = 18; // 编译器看你赋值18,自动推断 age 是 int注意:var 不是没有类型,而是编译器帮你填了类型。一旦确定,之后就不能把其他类型(比如字符串)塞给 age 了,因为 C# 是强类型语言。
接下来我们要进入本篇的深水区。这是面试必问,也是新手必坑。
C# 的数据类型分为两大派系:
int, double, bool, char, struct, enumstring, class, array, interface它们最大的区别在于:当你把一个变量赋值给另一个变量时,发生了什么?
// 值类型实验int a = 10;int b = a; // 把 a 赋值给 bb = 20; // 修改 bConsole.WriteLine($"a: {a}, b: {b}");// 输出:a: 10, b: 20结果: 修改 b,a没变。这很符合直觉,对吧?
我们定义一个简单的“玩家”类(先别管类的语法,看逻辑):
classPlayer { publicstring Name; }// 引用类型实验Player p1 = new Player();p1.Name = "Pipi";Player p2 = p1; // 把 p1 赋值给 p2p2.Name = "Guagua"; // 修改 p2 的名字Console.WriteLine($"p1: {p1.Name}, p2: {p2.Name}");// 输出:p1: Guagua, p2: Guagua结果: 居然变了!我明明只改了 p2,为什么 p1 也变成了 "Guagua"?
为了解释上面的灵异现象,我们需要看看内存里发生了什么。请看下图:
int, bool 这些类型主要住在栈上。
int b = a; 时,C# 是把 a 的值复印了一份给 b。a 和 b 是两张完全独立的纸。你在 b 上涂鸦,当然不会影响 a。
Player, string 等对象住在堆上。
p1 并没有把“整个玩家对象”存在栈里(因为对象可能很大)。p1 在栈里存的,只是一个地址(引用),就像一把钥匙,或者是这个对象的遥控器。关键时刻:当你执行 Player p2 = p1; 时:
p1 和 p2 两个变量手里拿着同一把钥匙,指向同一个堆内存里的对象。p2 修改了名字,p1 再去看的时候,名字自然也变了。
有人会问:“既然 string 是引用类型,那为什么 string b = a; b = "new"; 之后 a 不变呢?”
这是因为 C# 里的字符串具有不可变性 (Immutability)。 当你给字符串变量重新赋值时,它并没有修改堆里原来的字,而是在堆里新建了一个新字符串,然后把变量的“遥控器”指向了新地址。
今天我们不仅学习了变量的定义,还窥探了内存的秘密:
🧠 课后思考题:如果我想复制一个 Player 对象,让 p2 和 p1 即使改名也互不影响(即深拷贝),应该怎么办呢?
下一期,我们将让程序学会“思考”,学习 if/else 和循环,控制逻辑的流动!