C# 结构体(Struct)
C# 结构体(struct)是一种值类型的数据结构,它在内存中分配空间时与类(class)不同。结构体通常用于封装较小的数据块,它有助于提升性能,特别是在大量对象创建的场景中。结构体的行为与类有很多相似之处,但它的内存管理和使用场景有所不同。
一、结构体的基本概念
- 值类型:结构体是值类型(不像类是引用类型)。这意味着,当你将结构体赋值给另一个变量时,会创建该结构体的副本,而不是引用同一个对象。
- 不能继承:结构体不能继承其他结构体或类,也不能被继承。
- 自动包含无参构造函数:每个结构体都包含一个默认的无参数构造函数,但你不能自定义无参构造函数。可以定义带参数的构造函数。
二、定义结构体
结构体的定义类似于类,但用 struct 关键字来声明。
struct Point
{
public int X;
public int Y;
// 带参数的构造函数
public Point(int x, int y)
{
X = x;
Y = y;
}
}
三、创建和使用结构体
你可以像使用类一样创建和使用结构体,但结构体是值类型,因此它们的行为有所不同。
Point p1 = new Point(10, 20); // 使用带参数的构造函数
Console.WriteLine($"X: {p1.X}, Y: {p1.Y}"); // 输出 X: 10, Y: 20
Point p2 = p1; // 创建副本
p2.X = 30; // 修改副本的值
Console.WriteLine($"p1.X: {p1.X}, p2.X: {p2.X}"); // 输出 p1.X: 10, p2.X: 30
✅ 结构体是值类型,所以修改
p2不会影响p1。
四、结构体的常见操作
| 操作方法 | 示例 | 说明 |
|---|---|---|
new | Point p = new Point(5, 10); | 使用构造函数初始化结构体 |
ToString() | point.ToString() | 返回结构体的字符串表示 |
Equals() | point1.Equals(point2) | 比较两个结构体是否相等 |
GetHashCode() | point.GetHashCode() | 获取结构体的哈希值 |
五、结构体的性能特点
- 值类型分配在栈上:结构体实例通常分配在栈上,而类实例分配在堆上。栈的内存分配和回收速度比堆快,因此结构体可以避免堆分配的开销。
- 避免垃圾回收:因为结构体是值类型,它们不需要垃圾回收(GC),这减少了运行时开销。
✅ 适合频繁创建、销毁的小对象(如坐标、颜色等)。
六、结构体的注意事项
- 不可为
null:结构体是值类型,因此不能为null,除非使用 可空类型(Nullable)。
Point? p = null; // 可空结构体
- 不能继承:结构体不能继承其他结构体或类,也不能被继承。
- 不能定义默认构造函数:结构体的默认构造函数是由编译器自动提供的,不能显式定义无参构造函数。
七、结构体示例:表示二维点
struct Point
{
public int X;
public int Y;
public Point(int x, int y)
{
X = x;
Y = y;
}
public double DistanceTo(Point other)
{
return Math.Sqrt(Math.Pow(other.X - X, 2) + Math.Pow(other.Y - Y, 2));
}
public override string ToString()
{
return $"({X}, {Y})";
}
}
使用结构体:
Point p1 = new Point(3, 4);
Point p2 = new Point(6, 8);
Console.WriteLine($"Point 1: {p1}");
Console.WriteLine($"Point 2: {p2}");
Console.WriteLine($"Distance: {p1.DistanceTo(p2)}");
八、结构体的比较与相等性
C# 默认会使用 逐字段比较 来判断结构体的相等性。你可以重写 Equals 方法来定义自定义的相等性比较。
struct Point
{
public int X;
public int Y;
public override bool Equals(object obj)
{
if (obj is Point)
{
Point p = (Point)obj;
return X == p.X && Y == p.Y;
}
return false;
}
public override int GetHashCode()
{
return X.GetHashCode() ^ Y.GetHashCode();
}
}
九、结构体的适用场景
1. 简单的数据结构
适用于表示一组小的、封装的数据(例如:坐标、颜色、矩阵等)。
2. 性能优化
由于结构体是值类型,因此可以避免垃圾回收和堆内存分配的开销,特别是在频繁创建小对象时(例如:游戏开发中的位置、速度等物理属性)。
3. 线程安全
值类型(结构体)是线程安全的,因为每个线程处理的是独立的副本。
十、参考文献和文档
更多详细内容,请关注其他相关文章!