C# 变量声明与作用域
变量是程序里"装数据的盒子"。C# 是一门静态强类型语言,每个变量都有明确的类型,编译器在编译期检查类型匹配——类型不对直接报错。这一篇我们搞懂 C# 变量的几种声明方式、常量、作用域规则。
一、三种声明方式
C# 里声明变量主要有三种写法,日常开发中最常用的是 var(配合强类型推断)。先看一个综合示例:
// 1. 显式声明:类型 + 变量名 + 可选初值
int age = 25;
double price = 9.99;
string name = "小明";
bool isStudent = true;
// 2. var:让编译器推断类型(局部变量常用)
var city = "北京"; // string
var count = 100; // int
var nums = new int[] {1, 2, 3}; // int[]
// 3. 先声明后赋值(不推荐,容易忘初始化)
int score;
score = 88;几个要点:
- 显式声明:类型写明,最清晰。适合公共 API、字段声明。
var:编译器根据右侧值推断类型。它是语法糖——编译完就变成具体类型了,不是动态类型。局部变量推荐用 var。- 先声明后赋值:不常用,容易忘初始化。C# 不允许读未赋值的局部变量。
var 的好处是简洁——尤其是类型名很长时(如 Dictionary<string, List<int>>)。但要注意:var 只能用于局部变量,不能用于字段、参数、返回值;必须有初值供编译器推断。
二、命名规范
C# 变量命名遵循camelCase(小驼峰),首字母小写:
- ✅
userNametotalCountisReady - ❌
user_name(下划线风格是 C/C++/Python 的习惯,不是 C# 主流) - ❌
UserName(这是 PascalCase,留给类名/方法名/属性) - ❌
xy(除非是循环计数或临时变量)
命名要"见名知意",userAge 比 a 好,activeUserCount 比 count 好。这是写可维护代码的基础。
三、常量:const 与 readonly
"常量"是不能修改的值。C# 有两个相关关键字,容易混淆:
// const:编译时常量,必须初始化,之后不能改
const double Pi = 3.14159;
const int MaxRetry = 3;
const string AppName = "MyApp";
// ❌ 错误:const 不能改
// Pi = 3.14;
// readonly:运行时常量(只能在声明时或构造函数里赋值)
public class Configuration
{
public readonly DateTime CreatedAt;
public Configuration()
{
CreatedAt = DateTime.Now; // 运行时才知道的值
}
}区别如下:
const:编译时常量,值在编译时就确定。隐式 static,只能用于简单类型(数字、字符串)。声明时必须赋值,之后永不改变。readonly:运行时常量,可以在声明时或构造函数里赋值。每个实例可以有不同的值(非 static 时)。
简单记:能用 const 就用 const(编译器优化更好);如果值需要运行时确定(如 DateTime.Now)或要每个实例不同,就用 readonly。
四、默认值
C# 保证所有变量都有确定的初始值。字段(类成员)即使你不显式赋值,也会被自动初始化为默认值;但局部变量必须先赋值再读,否则编译报错。默认值规则:
- 数值类型(int、double 等):
0 - 布尔类型 bool:
false - 字符 char:
'\\0'(空字符) - 引用类型(string、object、所有 class):
null - 枚举 enum:
0(第一个枚举值,如果没显式赋值) - 结构体 struct:每个字段递归取默认值
可以用 default 关键字显式获取:
using System;
// default 关键字获取类型的默认值
int a = default; // 0
bool b = default; // false
string c = default; // null
DateTime d = default; // 0001-01-01 00:00:00
// 显式写法:default(T)
int e = default(int); // 0五、变量的作用域
作用域指变量"在哪些代码范围里能被访问"。C# 的作用域分三层:
using System;
public class Demo
{
private int instanceField = 10; // 字段(类作用域)
public void Method()
{
int local = 20; // 局部变量(方法作用域)
if (true)
{
int block = 30; // 块作用域
Console.WriteLine(block); // 30
}
// ❌ 错误:block 在这里不可见
// Console.WriteLine(block);
}
}- 类作用域(字段):在类里声明的变量,整个类的所有方法都能用。也叫"成员变量"或"字段"。
- 方法作用域(局部变量):在方法内部声明,只在该方法内可见,方法返回后消失。
- 块作用域:在
if、for、while等花括号内部声明,出了这对花括号就不可见。
规则:内层可以访问外层,外层不能访问内层;如果内外层同名,内层遮蔽外层(C# 会发出警告,建议改名避免)。
六、类型推断 vs 动态类型
var 是编译期推断,编译完类型就固定了,不是动态类型。如果你想要运行时改变类型,可以用 dynamic(C# 4+),但不推荐——会绕过编译期检查,容易运行时崩溃:
// var:编译期确定类型
var x = 10;
// x = "hello"; // ❌ 编译报错,x 是 int
// dynamic:运行时确定类型(慎用)
dynamic y = 10;
y = "hello"; // ✅ 编译通过,但 y = "a" + 1 这种隐藏 bug 难发现
// object:类似 dynamic 但要装箱,访问成员需类型转换
object z = 10;
int n = (int)z; // 显式转换实际开发 99% 用 var。dynamic 主要在调用 Python、COM、JSON 解析等场景用,日常慎用。
七、字符串插值
这是初学者最先接触到的"小而美"特性——字符串前加 $,用花括号嵌入变量:
string name = "小明";
int age = 20;
// 字符串插值(C# 6+ 推荐)
string s1 = $"我叫{name},今年{age}岁。";
// 我叫小明,今年20岁。
// 传统拼接(可读性差)
string s2 = "我叫" + name + ",今年" + age + "岁。";
// string.Format(老写法)
string s3 = string.Format("我叫{0},今年{1}岁。", name, age);
// 还能在花括号里写表达式
string s4 = $"明年我{age + 1}岁";字符串插值是 C# 写法的现代首选,可读性碾压拼接和 Format。
小结
记住这几条就够用了:局部变量优先用 var,字段写显式类型;常量用 const(编译时)或 readonly(运行时);变量必须先赋值再用;作用域跟着花括号走。下一篇我们看 C# 的数据类型系统——这是强类型语言的核心。
← 上一篇 C# 基础语法
下一篇 C# 数据类型 →