03-变量和常量
变量和常量是 C# 程序中存储和使用数据的两种基本方式。变量的值可以改变,常量的值在声明后不可修改。
一、变量(Variable)
1. 什么是变量
变量是内存空间的符号化表示。程序通过变量名来访问和操作内存中的数据。
变量声明 → 编译器分配内存 → 通过变量名读写数据2. 变量声明
csharp
// 声明并初始化
int age = 30;
string name = "张三";
double price = 99.9;
// 先声明后赋值
int num; // 声明(默认值为 0)
num = 10; // 赋值
// 注意:变量在使用前必须赋值
int x;
// Console.WriteLine(x); // ❌ 错误:使用了未赋值的变量
// 同时声明多个变量
int a = 0, b, c; // a 已初始化,b 和 c 未初始化
b = 1;
c = 2;3. 变量的数据类型
| 类型分类 | 示例 | 内存大小 |
|---|---|---|
| 值类型 | int, double, bool, char | 固定大小 |
| 引用类型 | string, class, array | 可变大小(引用在栈,数据在堆) |
| var 隐式类型 | var a = 10; | 由编译器推断 |
4. 变量作用域
变量的作用域从声明位置开始,到所在块的末尾结束。
csharp
class Program
{
static int globalCounter = 0; // 类级变量(静态字段),整个类可访问
static void Main()
{
int a = 10; // Main 方法中的变量
if (true)
{
int b = 20; // if 块中的变量
Console.WriteLine(a); // ✅ 子级作用域可以访问父级变量
}
// Console.WriteLine(b); // ❌ 超出作用域,无法访问
}
static void OtherMethod()
{
// Console.WriteLine(a); // ❌ 不同方法的作用域隔离
}
}作用域嵌套规则
| 规则 | 说明 | 示例 |
|---|---|---|
| 子级访问父级 | 内部块可访问外部块的变量 | if 块内可访问 Main 的变量 |
| 父级不能访问子级 | 外部块不能访问内部块的变量 | Main 中不能访问 if 块内的变量 |
| 同级相互隔离 | 同级代码块变量独立 | 两个 if 块中的变量互不干扰 |
| 同名限制 | 子级不能声明与父级同名的变量 | if 块内不能声明和 Main 中同名的变量 |
csharp
// 同级作用域互不影响
if (true)
{
int x = 10;
}
if (true)
{
int x = 20; // ✅ 合法的,与上一个 if 块的 x 无关
}
// 嵌套作用域不能重名
int y = 10;
if (true)
{
// int y = 20; // ❌ 错误:与父级作用域的 y 冲突
}二、var 隐式类型变量
var 让编译器根据初始值推断变量类型,是隐式类型而非动态类型。
csharp
// 基本用法
var number = 10; // int
var price = 99.9m; // decimal
var name = "张三"; // string
var items = new List<int>(); // List<int>
// 匿名类型(必须用 var)
var person = new { Name = "张三", Age = 25 };
// 注意事项
// var x; // ❌ 必须初始化
// var y = null; // ❌ 不能推断为 null
// var z = (string)null; // ❌ 也不行,类型不明确
// 使用建议:右侧能明确看出类型时使用
var dict = new Dictionary<string, List<int>>(); // ✅ 好(类型名太长)
// var result = GetData(); // ⚠️ 当返回类型不明确时,应显式声明三、常量(Constant)
1. const 常量
使用 const 关键字声明,值在编译时确定,无法修改。
csharp
const int MaxRetryCount = 3;
const double PI = 3.1415926;
const string AppName = "MyApp";
// 常量必须在声明时初始化
// const int X; // ❌ 错误
// 常量不能修改
// MaxRetryCount = 5; // ❌ 错误
// 常量可以参与运算
int retryCount = MaxRetryCount; // ✅const 的限制
csharp
// const 只能用于基本类型(内建值类型 + string)
const int IntConst = 1; // ✅
const string StrConst = "Hello"; // ✅
const double DblConst = 3.14; // ✅
// const 不能用于引用类型(除 string 外)
// const DateTime DateConst = DateTime.Now; // ❌ 错误
// const Random RandConst = new Random(); // ❌ 错误2. readonly 只读字段
readonly 在运行时确定值,只能在声明时或构造函数中赋值。
csharp
public class Config
{
// 声明时初始化
public readonly DateTime CreateTime = DateTime.Now;
// 也可以在构造函数中赋值
public readonly Guid Id;
public Config()
{
Id = Guid.NewGuid(); // ✅ 构造函数中可以修改 readonly
}
public void Update()
{
// Id = Guid.NewGuid(); // ❌ 方法中不能修改 readonly
}
}const vs readonly 对比
| 对比项 | const | readonly |
|---|---|---|
| 赋值时机 | 编译时 | 运行时 |
| 初始化 | 声明时必须初始化 | 声明时或构造函数中 |
| 数据类型 | 仅基本类型 + string | 任意类型 |
| 内存分配 | 编译时嵌入到代码中 | 运行时分配内存 |
| 应用场景 | 真正的常量(圆周率、重试次数) | 运行期确定的不可变值(ID、创建时间) |
| 静态/实例 | 隐式静态 | 可以是实例字段或静态字段 |
csharp
public class Constants
{
// const——编译时常量
public const double PI = 3.14159;
public const int MaxRetries = 3;
// static readonly——运行时常量(类级别)
public static readonly DateTime AppStartTime = DateTime.Now;
public static readonly string MachineName = Environment.MachineName;
// readonly——实例级别只读字段
public readonly Guid InstanceId = Guid.NewGuid();
}四、变量的初始化默认值
C# 中不同类型的变量有各自的默认值:
| 类型 | 默认值 |
|---|---|
| 数值类型(int, long, double 等) | 0 / 0.0 |
| bool | false |
| char | \0(空字符) |
| string | null |
| 引用类型(class, array 等) | null |
csharp
int defaultInt = default; // 0
bool defaultBool = default; // false
string defaultString = default; // null
DateTime defaultDate = default; // 0001/1/1 0:00:00核心知识点总结
变量 vs 常量
| 对比项 | 变量 | 常量(const) |
|---|---|---|
| 值是否可变 | 可修改 | 不可修改 |
| 关键字 | 类型名 | const + 类型名 |
| 初始化 | 声明时可选 | 声明时必须 |
| 存储 | 运行时分配 | 编译时嵌入 |
| 用途 | 存储变化的数据 | 存储固定值 |
命名约定
| 类型 | 规范 | 示例 |
|---|---|---|
| 局部变量 | camelCase | userName, totalCount |
| 私有字段 | _camelCase | _userName, _connection |
| 常量 | PascalCase | MaxRetryCount |
| 参数 | camelCase | string name |
注意事项
- 变量在使用前必须赋值——否则编译错误
- const 是编译时常量——修改 const 值需要重新编译引用它的所有程序集
- readonly 是运行时常量——不同实例可以有不同的 readonly 值
- var 不是动态类型——编译时已确定,不能改变
- 变量名区分大小写——
name和Name是两个不同的变量 - 避免过长的变量作用域——变量作用域越小越好,降低出错概率
- 常量命名通常用 PascalCase——而非全大写下划线风格(那是 C/C++ 风格)


