====== C# 变量作用域与数据类型 ======
===== 变量作用域使用范围 =====
在 C# 中,变量的可访问性取决于其定义的位置和修饰符。
* **类级变量(字段)**:一个类里面定义的变量,默认情况下不能在该类之外直接使用。
* **默认修饰符**:类成员默认是 `private`(私有),仅限类内部访问。
* **公开访问**:若需外部访问,需使用 `public` 修饰。
* **静态访问**:若使用 `static` 修饰,则该变量属于类本身,而非类的实例,可通过 `类名.变量名` 访问。
===== 变量类型 =====
C# 的数据类型主要分为三大类:
{{.:pasted:20251120-142725.png}}
* **值类型 (Value Types)**:数据直接存储在**栈 (Stack)** 上。包含:整数、浮点数、布尔值、字符、结构体 (struct)、枚举 (enum)。
* **引用类型 (Reference Types)**:数据存储在**堆 (Heap)** 上,栈中只存储指向堆内存的地址(引用)。包含:类 (class)、接口 (interface)、数组、字符串 (string)、委托 (delegate)。
* **指针类型 (Pointer Types)**:用于直接操作内存地址,需在 `unsafe` 模式下使用。
引用类型不进行转换,直接引用地址,程序效率会快一点。
===== 值类型详解 =====
==== 基础值类型范围 ====
{{.:pasted:20251010-152216.png}}
==== 浮点数类型注意事项 ====
{{.:pasted:20251010-152251.png}}
在 C# 中,带小数点的数值默认为 `double` 类型。如果需要定义 `float` 类型,必须在数值后添加后缀 **f** 或 **F**。
// 错误写法:编译器报错,无法将 double 隐式转换为 float
float myFloat = 3.14;
// 正确写法
float myFloat = 3.14f;
double myDouble = 3.14;
decimal myDecimal = 3.14m; // 金额计算通常使用 decimal
{{.:pasted:20251013-092619.png}}
===== 引用类型详解 =====
{{.:pasted:20251013-092701.png}}
==== 引用类型的内存理解 (1) ====
**核心区别:**
- **值类型**:创建时,值直接保存在**栈**里。
- **引用类型**:创建时,对象(数据实体)保存在**堆**里,而**栈**里保存的是指向该堆内存地址的“指针”(引用)。
{{.:pasted:20251013-092736.png}}
{{.:pasted:20251013-092743.png}}
> **总结**:
> * 使用**值类型**时,变量之间是独立的。修改一个变量的值**不会**影响其他变量。
> * 使用**引用类型**时,如果两个变量指向同一个对象,修改其中一个变量引用的对象内容,**会影响**到另一个变量(因为它们指向同一块内存)。
==== 引用类型的内存理解 (2) - 代码案例 ====
请看以下代码示例,观察 `Stime2` 和 `Stime3` 的行为:
class Ceshi
{
public string Name { get; set; }
public int Age { get; set; }
}
static class TestClass
{
public static void Function()
{
// 1. 值类型赋值(结构体或基本类型)
// 假设 int 是值类型
Ceshi Stime1 = new Ceshi() { Name = "A", Age = 25 };
int age = Stime1.Age; // age 获得了 25 的副本
Stime1.Age = 35; // 修改 Stime1 不会影响局部变量 age
// 2. 引用类型赋值(类)
Ceshi Stime2 = new Ceshi() { Name = "B", Age = 30 };
// 关键点:这里是将 Stime2 的引用(地址)赋给了 Stime3
// 此时 Stime2 和 Stime3 指向堆内存中的同一个对象
Ceshi Stime3 = Stime2;
// 修改 Stime2 指向对象的属性
Stime2.Name = "C";
// 输出结果
Console.WriteLine("Stime1 Age 的值 :" + Stime1.Age); // 输出 35
Console.WriteLine("局部变量 age 的值 :" + age); // 输出 25 (未变)
Console.WriteLine("Stime2 Name 的值 :" + Stime2.Name); // 输出 C
Console.WriteLine("Stime3 Name 的值 :" + Stime3.Name); // 输出 C (因为指向同一个对象)
}
}
==== 通用类型 Object ====
`object` 是所有类型的基类。任何类型都可以赋值给 `object`。
{{.:pasted:20251013-092906.png}}
object num1 = 3.14; // 装箱:值类型转引用类型
object num2 = "工控机"; // 字符串本身就是引用类型
object num3 = 145;
==== 类的引用与绑定理解 ====
当多个引用变量指向同一个实例时,使用其中任何一个变量操作成员,效果是等同的。
例如:使用 `fuka` 对象就等于使用 `zhuka` 对象成员(前提是它们指向同一地址)。
{{.:pasted:20251013-092934.png}}
===== 指针类型 (Pointer) =====
指针类型用于直接操作内存地址,类似于 C/C++。在 C# 中使用指针必须在 `unsafe` 代码块中,并且项目属性需要开启“允许不安全代码”。
===== 自定义变量类型:枚举 (Enum) =====
==== 简介 ====
枚举 (Enumeration) 是一种值类型,用于定义一组命名的**整型常量**。
* **特点**:增强代码可读性,避免使用魔术数字。
* **赋值**:定义枚举变量时,必须为其赋一个枚举内部定义的值。
* **传递**:枚举可以像普通变量一样作为参数传递。
{{.:pasted:20251013-092955.png}}
==== 使用步骤 ====
- **Step 1**:声明枚举类型,列出包含的成员名称(默认从0开始递增)。
- **Step 2**:使用该类型定义变量,并赋值。
==== 枚举案例 1:星期 ====
// 创建枚举类型
public enum DaysOfWeek
{
Sunday, // 默认值 0
Monday, // 默认值 1
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday
}
// 使用枚举
class Program {
static void Main() {
// 定义枚举类型变量并赋值
DaysOfWeek today = DaysOfWeek.Monday;
if (today == DaysOfWeek.Saturday || today == DaysOfWeek.Sunday)
{
Console.WriteLine("It's weekend!");
}
else
{
Console.WriteLine("It's a weekday.");
}
}
}
==== 枚举案例 2:数学运算 ====
假设有一个名为 `Operations` 的枚举,用于表示不同的数学运算:
public enum Operations
{
Add,
Subtract,
Multiply,
Divide
}
// 定义一个静态函数,参数3为枚举类型
public static double PerformOperation(double num1, double num2, Operations operation)
{
switch (operation)
{
case Operations.Add:
return num1 + num2;
case Operations.Subtract:
return num1 - num2;
case Operations.Multiply:
return num1 * num2;
case Operations.Divide:
if (num2 != 0)
return num1 / num2;
else
throw new ArgumentException("Cannot divide by zero.");
default:
throw new ArgumentException("Invalid operation.");
}
}