3、C#语言基础(上):变量与数据类型、常量、类型转换、运算符与表达式

好,咱们正式开始写代码了。C# 这门语言,说白了就是围绕「数据」转的。你写任何程序,本质上都是在处理数据——存起来、算一算、再输出。所以这一章,咱们先把数据的基本玩法搞清楚。

3.1 变量:数据的容器

变量是什么?你可以把它想象成一个带标签的盒子。盒子里能装东西,标签上写着盒子的名字。在 C# 里,用变量之前必须先声明——告诉编译器:「嘿,我要一个盒子,叫 age,里面放整数。」

int age;          // 声明一个整数变量
age = 25;         // 赋值
int score = 90;   // 声明并初始化,一步到位

我个人习惯在声明变量时就给个初始值。为什么?因为 C# 不允许使用未赋值的局部变量。你想想看,要是你打开一个空盒子,里面有什么?鬼知道。编译器干脆就不让你用,省得出 bug。

命名规范:C# 里变量名用驼峰命名法(camelCase),比如 myAgestudentName。别用拼音,也别用 a、b、c 这种无意义的名字。我在项目中见过有人用 aaabbb 命名,三个月后他自己都看不懂了。

3.2 数据类型:盒子的大小和形状

C# 是强类型语言。什么意思?每个变量都有固定的类型,不能今天装整数,明天装字符串。类型决定了数据在内存里占多大空间、能做什么操作。

3.2.1 值类型 vs 引用类型

这是 C# 里一个很重要的概念。值类型直接存数据,引用类型存的是数据的地址。打个比方:值类型就像你直接把钱揣兜里,引用类型就像你把钱存银行,兜里只放一张银行卡。

类别 常见类型 存储位置
值类型 int, double, bool, char, struct 栈(Stack)
引用类型 string, class, array, object 堆(Heap)

3.2.2 常用数据类型一览

咱们挑几个最常用的说说:

  • int:32 位整数,范围 ±21 亿。够用 99% 的场景。
  • long:64 位整数,数星星都够了。
  • float / double:浮点数。float 精度 7 位,double 15 位。我一般直接用 double,省心。
  • decimal:高精度小数,适合金融计算。记得加 m 后缀:decimal price = 19.99m;
  • bool:只有 true 和 false。别写 if (isOK == true),直接 if (isOK) 就行。
  • string:字符串。注意它是引用类型,但行为上有点像值类型,面试常考这个。
  • char:单个字符,用单引号:'A'
避坑指南:我曾经在项目里用 float 存金额,结果累加时差了 0.01 元。财务部门追着我改了一整天。从那以后,凡是跟钱有关的,我全用 decimal。

3.3 常量:不变的值

有些数据在程序运行期间不能变,比如圆周率、税率、配置参数。这时候就用 const 关键字。

const double PI = 3.1415926;
const int MAX_RETRY_COUNT = 3;

常量有几个特点:声明时必须赋值,之后不能改。而且它是在编译时就确定的,所以不能用在运行时才能知道的值上。如果你需要一个运行时常量,用 readonly 关键字,这个咱们后面再讲。

我个人习惯把常量名全大写,单词间用下划线。这不是 C# 的强制要求,但很多团队都这么约定,一眼就能看出来这是个常量。

3.4 类型转换:数据变形记

实际开发中,你经常需要把一种类型转成另一种。比如用户输入的是字符串,你要转成数字才能做计算。C# 提供了几种转换方式。

3.4.1 隐式转换

从小范围到大范围,编译器自动帮你转。比如 int 转 long、float 转 double。因为不会丢数据,所以放心转。

int i = 100;
long l = i;   // 隐式转换,没问题
double d = i; // 也是隐式转换

3.4.2 显式转换(强制转换)

从大范围到小范围,可能丢数据,必须你手动告诉编译器:「我知道风险,我负责。」

double d = 3.14;
int i = (int)d;  // i 变成 3,小数部分丢了

嗯,这里要注意:强制转换不会四舍五入,直接截断。如果你需要四舍五入,用 Math.Round()

3.4.3 Convert 类转换

最常用的转换方式,尤其是字符串转数字的时候。

string input = "123";
int number = Convert.ToInt32(input);

如果字符串格式不对,Convert 会抛出异常。所以实际项目中,我一般配合 try-catch 或者用 int.TryParse() 来安全转换。

注意:Convert.ToInt32() 转换 null 时,会返回 0。而 int.Parse(null) 会直接抛异常。这个区别在面试里经常被问到。

3.4.4 使用 Parse 和 TryParse

// Parse:转换失败就抛异常
int a = int.Parse("123");

// TryParse:转换失败返回 false,不会抛异常
string s = "abc";
if (int.TryParse(s, out int result))
{
    Console.WriteLine($"转换成功:{result}");
}
else
{
    Console.WriteLine("转换失败");
}

我个人强烈推荐 TryParse。为什么?因为用户输入永远不可信。我曾经在项目中用 Parse,结果用户输了个「十二」,程序直接崩溃。用 TryParse 优雅处理,用户体验好得多。

3.5 运算符与表达式:让数据动起来

有了数据,接下来就是怎么操作它们。运算符就是干这个的。

3.5.1 算术运算符

加减乘除取模,跟数学课上学的差不多。

int a = 10, 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(取模,就是余数)

这里有个坑:两个整数相除,结果还是整数。如果你想要小数结果,至少让其中一个操作数是浮点数。

double result = 10 / 3;      // 结果是 3.0,不是 3.333
double correct = 10.0 / 3;   // 结果是 3.333...

3.5.2 赋值运算符

除了基本的 =,还有复合赋值运算符,写起来更简洁。

int x = 5;
x += 3;  // 等价于 x = x + 3
x -= 2;  // 等价于 x = x - 2
x *= 4;  // 等价于 x = x * 4
x /= 2;  // 等价于 x = x / 2
x %= 3;  // 等价于 x = x % 3

3.5.3 比较运算符

比较的结果是 bool 类型,要么 true 要么 false。

int age = 18;
bool isAdult = age >= 18;  // true
bool canDrive = age >= 16; // true
bool isEqual = (age == 18); // true,注意是两个等号

新手最容易犯的错误:把 == 写成 =。在 C# 里,if (a = 5) 会编译报错,因为赋值表达式的结果是 int 类型,不能当 bool 用。这一点比 C/C++ 安全多了。

3.5.4 逻辑运算符

用来组合多个条件。

bool hasLicense = true;
bool hasInsurance = false;

// && 与:两个都 true 才 true
bool canRent = hasLicense && hasInsurance; // false

// || 或:一个 true 就 true
bool canDrive = hasLicense || hasInsurance; // true

// ! 非:取反
bool cannotDrive = !canDrive; // false

逻辑运算符有短路特性。比如 A && B,如果 A 是 false,B 根本不会执行。这个特性有时候可以用来做优化,但也要小心别写出依赖副作用的代码。

3.5.5 自增自减运算符

写循环时经常用到。

int count = 0;
count++;  // count 变成 1,等价于 count = count + 1
count--;  // count 变回 0

// 前缀和后缀的区别
int a = 5;
int b = a++;  // b = 5,a = 6(先赋值,后自增)
int c = ++a;  // a = 7,c = 7(先自增,后赋值)

我个人建议:除非你很清楚自己在做什么,否则别把自增自减写在复杂表达式里。单独一行用,清晰明了。

3.6 表达式:组合的艺术

把变量、常量和运算符组合起来,就构成了表达式。每个表达式都有一个计算结果,这个结果有类型。

int result = (10 + 5) * 2 - 8 / 4;  // 结果是 28

运算符有优先级,跟数学一样:先乘除后加减,括号最优先。记不住优先级怎么办?加括号。括号不仅让代码更清晰,还能避免一些奇怪的 bug。

核心原则:写代码是给人看的,顺便给机器执行。别耍小聪明写一行很复杂的表达式。拆成多行,加个中间变量,可读性比「看起来很厉害」重要得多。

好了,这一章的内容就这些。变量、数据类型、常量、类型转换、运算符——这些都是 C# 的「砖块」。后面的章节,咱们就用这些砖块搭房子了。下一章咱们继续聊 C# 语言基础的下半部分:流程控制、数组和字符串操作。