Skip to content

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 对比

对比项constreadonly
赋值时机编译时运行时
初始化声明时必须初始化声明时或构造函数中
数据类型仅基本类型 + 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
boolfalse
char\0(空字符)
stringnull
引用类型(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 + 类型名
初始化声明时可选声明时必须
存储运行时分配编译时嵌入
用途存储变化的数据存储固定值

命名约定

类型规范示例
局部变量camelCaseuserName, totalCount
私有字段_camelCase_userName, _connection
常量PascalCaseMaxRetryCount
参数camelCasestring name

注意事项

  1. 变量在使用前必须赋值——否则编译错误
  2. const 是编译时常量——修改 const 值需要重新编译引用它的所有程序集
  3. readonly 是运行时常量——不同实例可以有不同的 readonly 值
  4. var 不是动态类型——编译时已确定,不能改变
  5. 变量名区分大小写——nameName 是两个不同的变量
  6. 避免过长的变量作用域——变量作用域越小越好,降低出错概率
  7. 常量命名通常用 PascalCase——而非全大写下划线风格(那是 C/C++ 风格)

Released under the MIT License.