C# 变量作用域
局部、块级、类级、静态,以及 `using` 声明的生命周期。
Key Points变量在哪个 `{}` 里声明就活到那个 `{}` 结束;字段活到对象被回收。
三种作用域
C#
class Demo
{
int field = 1; // 字段:整个对象生命周期
static int shared = 2; // 静态字段:整个进程
void Run()
{
int local = 3; // 局部变量:方法调用期间
Console.WriteLine($"{field} {shared} {local}");
for (int i = 0; i < 2; i++)
{
int inLoop = i * 10; // 块级:只在 for 体内
Console.WriteLine(inLoop);
}
// Console.WriteLine(inLoop); // 编译错误
}
}
new Demo().Run();Output
1 2 3
0
10嵌套与遮蔽
C#
int x = 1;
{
int y = 2;
Console.WriteLine($"{x} {y}");
}
// y 在这里不存在
// 同一作用域不能重复声明
// int x = 5; // 编译错误
// 内层可以遮蔽外层(有警告 CS0136 在部分场景)
void Test()
{
int n = 1;
if (true)
{
int m = n + 1; // 用外层
Console.WriteLine(m);
}
}
Test();Output
1 2
2C# forbids declaring a local with the same name as an enclosing local (to avoid ambiguity) — stricter than JavaScript. When a field and a local share a name the local wins; use this.x for the field.
using 声明
C#
// 传统写法:块级,出块就释放
using (var reader = File.OpenText("a.txt"))
{
Console.WriteLine(reader.ReadLine());
}
// C# 8 起:using 声明,活到所在作用域结束
using var writer = File.CreateText("b.txt");
writer.WriteLine("内容");
// 方法结束时自动 Disposeusing var saves a level of indentation but lives to the end of the enclosing block. In a long method where you want an early release, use the block form.
静态字段的坑
C#
class Counter
{
public static int Count; // 所有实例共享
public int InstanceCount;
public Counter()
{
Count++;
InstanceCount++;
}
}
new Counter();
new Counter();
var c = new Counter();
Console.WriteLine(Counter.Count);
Console.WriteLine(c.InstanceCount);Output
3
1Static fields are not thread-safe.
Count++ is not atomic, so two threads can lose a count. Guard shared state with a lock or use Interlocked.Increment.值类型与作用域的交互
C#
void Modify(int x)
{
x = 999; // 改的是副本
}
int n = 1;
Modify(n);
Console.WriteLine(n); // 还是 1
void ModifyRef(ref int x)
{
x = 999;
}
ModifyRef(ref n);
Console.WriteLine(n); // 变了Output
1
999ref lets a method operate on the caller's variable itself. out is similar but requires assignment inside. Both are C#'s explicit pass-by-reference.
三种作用域
C#
class Demo
{
int field = 1; // 字段:整个对象生命周期
static int shared = 2; // 静态字段:整个进程
void Run()
{
int local = 3; // 局部变量:方法调用期间
Console.WriteLine($"{field} {shared} {local}");
for (int i = 0; i < 2; i++)
{
int inLoop = i * 10; // 块级:只在 for 体内
Console.WriteLine(inLoop);
}
// Console.WriteLine(inLoop); // 编译错误
}
}
new Demo().Run();Output
1 2 3
0
10嵌套与遮蔽
C#
int x = 1;
{
int y = 2;
Console.WriteLine($"{x} {y}");
}
// y 在这里不存在
// 同一作用域不能重复声明
// int x = 5; // 编译错误
// 内层可以遮蔽外层(有警告 CS0136 在部分场景)
void Test()
{
int n = 1;
if (true)
{
int m = n + 1; // 用外层
Console.WriteLine(m);
}
}
Test();Output
1 2
2C# 的规则是:子作用域不能声明与外层同名的局部变量(避免歧义),这一点比 JavaScript 严格。字段和局部变量同名时,局部优先,用 this.x 访问字段。
using 声明
C#
// 传统写法:块级,出块就释放
using (var reader = File.OpenText("a.txt"))
{
Console.WriteLine(reader.ReadLine());
}
// C# 8 起:using 声明,活到所在作用域结束
using var writer = File.CreateText("b.txt");
writer.WriteLine("内容");
// 方法结束时自动 Disposeusing var 比 using (...) 少一层缩进,但作用域更大——它活到所在方法或块结束。在长方法里想尽早释放句柄时,还是用块写法。
静态字段的坑
C#
class Counter
{
public static int Count; // 所有实例共享
public int InstanceCount;
public Counter()
{
Count++;
InstanceCount++;
}
}
new Counter();
new Counter();
var c = new Counter();
Console.WriteLine(Counter.Count);
Console.WriteLine(c.InstanceCount);Output
3
1静态字段在多线程下不安全。
Count++ 不是原子操作,两个线程同时执行会丢计数。共享状态要么加锁,要么用 Interlocked.Increment。值类型与作用域的交互
C#
void Modify(int x)
{
x = 999; // 改的是副本
}
int n = 1;
Modify(n);
Console.WriteLine(n); // 还是 1
void ModifyRef(ref int x)
{
x = 999;
}
ModifyRef(ref n);
Console.WriteLine(n); // 变了Output
1
999ref 让方法操作调用方的变量本身。out 类似但要求方法内必须赋值。这两个关键字就是 C# 里显式的「传引用」。