枚举与结构体
枚举(enum)
枚举是一种值类型,用于定义一组具名常量,使代码更具可读性和类型安全性。
定义枚举
使用 enum 关键字定义枚举,默认底层类型为 int,从 0 开始递增。
示例
CSHARP
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
class Program
{
static void Main()
{
Season current = Season.Autumn;
System.Console.WriteLine(current);
System.Console.WriteLine((int)current);
}
}
TEXT
Autumn
2
底层类型与显式赋值
枚举的底层类型默认为 int,可以显式指定为其他整数类型,并为成员赋予特定值。
示例
CSHARP
enum Priority : byte
{
Low = 1,
Medium = 2,
High = 3
}
enum HttpStatusCode
{
OK = 200,
NotFound = 404,
InternalServerError = 500
}
class Program
{
static void Main()
{
Priority p = Priority.High;
System.Console.WriteLine((byte)p);
System.Console.WriteLine((int)HttpStatusCode.NotFound);
}
}
TEXT
3
404
枚举转换
枚举与底层类型之间可以相互强制转换。
示例
CSHARP
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
class Program
{
static void Main()
{
Season s = Season.Spring;
int value = (int)s;
System.Console.WriteLine(value);
Season fromInt = (Season)2;
System.Console.WriteLine(fromInt);
}
}
TEXT
0
Autumn
Enum 类方法
System.Enum 类提供了多个静态方法用于枚举操作。
常用方法
| 方法 | 说明 |
|---|---|
Enum.Parse |
将字符串转为枚举,失败抛异常 |
Enum.TryParse |
将字符串转为枚举,失败返回 false |
Enum.GetName |
获取枚举值的名称 |
Enum.GetValues |
获取所有枚举值 |
Enum.IsDefined |
判断值是否在枚举中定义 |
示例
CSHARP
enum Season
{
Spring,
Summer,
Autumn,
Winter
}
class Program
{
static void Main()
{
Season parsed = (Season)Enum.Parse(typeof(Season), "Summer");
System.Console.WriteLine(parsed);
bool ok = Enum.TryParse<Season>("Winter", out Season result);
System.Console.WriteLine($"{ok}, {result}");
string name = Enum.GetName(typeof(Season), 2);
System.Console.WriteLine(name);
foreach (Season s in Enum.GetValues(typeof(Season)))
{
System.Console.WriteLine($"{s} = {(int)s}");
}
System.Console.WriteLine(Enum.IsDefined(typeof(Season), 1));
System.Console.WriteLine(Enum.IsDefined(typeof(Season), 99));
}
}
TEXT
Summer
True, Winter
Autumn
Spring = 0
Summer = 1
Autumn = 2
Winter = 3
True
False
结构体(struct)
结构体是一种值类型,适合封装小型数据。结构体存储在栈上,赋值时复制整个值。
定义结构体
使用 struct 关键字定义结构体。
示例
CSHARP
struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
public override string ToString()
{
return $"({X}, {Y})";
}
}
class Program
{
static void Main()
{
Point p1 = new Point(3, 4);
Point p2 = p1;
p2.X = 10;
System.Console.WriteLine(p1);
System.Console.WriteLine(p2);
}
}
TEXT
(3, 4)
(10, 4)
结构体 vs 类
结构体和类在语义和行为上有重要差异。
对比
| 特性 | struct | class |
|---|---|---|
| 类型类别 | 值类型 | 引用类型 |
| 存储位置 | 栈 | 堆 |
| 赋值行为 | 复制值 | 复制引用 |
| 继承 | 不支持(不能被继承) | 支持 |
| 接口 | 可以实现 | 可以实现 |
| 析构器 | 无 | 有 |
| 默认值 | 所有字段为零值 | null |
示例
CSHARP
struct PointStruct
{
public int X;
public int Y;
}
class PointClass
{
public int X;
public int Y;
}
class Program
{
static void Main()
{
PointStruct s1 = new PointStruct();
PointStruct s2 = s1;
s2.X = 5;
System.Console.WriteLine($"struct: s1.X={s1.X}, s2.X={s2.X}");
PointClass c1 = new PointClass();
PointClass c2 = c1;
c2.X = 5;
System.Console.WriteLine($"class: c1.X={c1.X}, c2.X={c2.X}");
}
}
TEXT
struct: s1.X=0, s2.X=5
class: c1.X=5, c2.X=5
结构体的适用场景
结构体并非在所有场景都优于类,应满足以下条件时考虑使用:
- 数据较小(建议 ≤16 字节)
- 逻辑上表示单个值(如坐标、颜色)
- 生命周期短,频繁创建销毁
- 不需要继承
常见示例:Point、Color、DateTime、TimeSpan。
⚠️ 不满足以上条件时使用 class,避免因频繁复制导致性能下降。
readonly struct(C# 7.2+)
readonly struct 保证所有字段不可变,编译器防止任何修改操作。
示例
CSHARP
readonly struct Point
{
public int X { get; }
public int Y { get; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public double DistanceTo(Point other)
{
int dx = X - other.X;
int dy = Y - other.Y;
return System.Math.Sqrt(dx * dx + dy * dy);
}
}
class Program
{
static void Main()
{
Point p1 = new Point(3, 4);
Point p2 = new Point(0, 0);
System.Console.WriteLine(p1.DistanceTo(p2));
}
}
TEXT
5
record struct(C# 10+)
record struct 结合了结构体的值语义与 record 的值相等性和简洁语法,适合需要不可变性和自动生成成员的场景。
示例
CSHARP
record struct Point(int X, int Y);
class Program
{
static void Main()
{
Point p1 = new Point(1, 2);
Point p2 = new Point(1, 2);
System.Console.WriteLine(p1 == p2);
System.Console.WriteLine(p1 with { X = 10 });
}
}
TEXT
True
Point { X = 10, Y = 2 }
💡
record struct 自动生成 Equals、ToString、with 表达式等成员,减少样板代码。
❓ 常见问题
Q 枚举可以指定非整数类型吗?
A 不可以,只能指定整数类型(byte、sbyte、short、ushort、int、uint、long、ulong)。
Q 结构体可以有构造函数吗?
A 可以有带参数的构造函数,但无参构造函数由编译器自动提供,不能自定义。
Q 结构体可以实现接口吗?
A 可以,结构体能实现接口,装箱为接口类型时会发生值到引用的转换。
Q readonly struct 的字段能用 set 吗?
A 不能,readonly struct 的所有字段必须为 readonly,只能通过构造函数初始化。
Q enum 和 const 有什么区别?
A enum 是一组具名常量的集合,具有类型安全性;const 是单个编译时常量,无类型分组能力。
📖 小节
- 枚举用
enum定义,默认底层类型为int,从 0 递增 - 可显式指定底层类型和成员值
Enum.Parse/TryParse/GetName/GetValues/IsDefined提供枚举操作- 枚举与底层类型之间可强制转换
- 结构体用
struct定义,是值类型,存储在栈上 - 结构体赋值复制值,类赋值复制引用
- 结构体不能被继承,但可以实现接口
- 适用场景:小数据(≤16字节)、不可变、短生命周期
readonly struct(C# 7.2+)保证所有字段不可变record struct(C# 10+)结合值语义与 record 简洁语法
📝 作业
- 定义一个
enum Direction { North, East, South, West },编写代码遍历所有方向并输出名称和整数值 - 定义一个
struct Rectangle,包含宽和高,提供计算面积的方法,并验证赋值时是值复制 - 将上题的
Rectangle改为readonly struct,确保所有字段只读,通过构造函数初始化 - 使用
Enum.TryParse和Enum.IsDefined编写一个安全的枚举解析方法,输入字符串返回对应枚举值或默认值 - 编写代码对比
struct和class在作为方法参数传递时的行为差异(值传递 vs 引用传递)



