1. 入门
结构体 —— 在C#里是一种特殊的数据类型,可以把几个值(甚至不同类型的)合成一个“小盒子”。就像乐高积木一样:你把零件拼起来,最后得到一个方便又紧凑的对象。
结构体和class很像,但有自己的特点,适合用在更“简单”的场景,不需要class那种“重量级”功能的时候。
语法
struct Point
{
public int X;
public int Y;
}
Point结构体的声明
在这个例子里,我们写了一个点的结构体,有X和Y坐标。
结构体一般用在哪?
结构体通常用来表示小型、简单的对象,这些对象要非常轻量,基本就是“纯数据”。
在C#里,有些标准类型其实就是结构体:
- int、double、bool、DateTime、TimeSpan、decimal、Guid
- 还有比如ConsoleKeyInfo或者Point(在图形库里)
结构体和class的区别
| 标准 | 结构体 | class |
|---|---|---|
| 关键字 | |
|
| 存储类型 | 值类型 | 引用类型 |
| 存储位置 | 栈(内存区域) | 堆(内存区域) |
| 传递到方法 | 按值传递(拷贝) | 按引用传递 |
| 继承 | 不支持(只能实现接口) | 支持 |
| 能不能是null | 不能(只能用Nullable) | 能 |
| 默认值 | 所有字段自动初始化为0 | 只能通过构造函数 |
2. 结构体的声明和使用
结构体可以在class里或者外面声明:
struct Rectangle
{
public int Width;
public int Height;
}
创建和使用结构体:
Rectangle r;
r.Width = 10;
r.Height = 5;
Console.WriteLine($"面积: {r.Width * r.Height}");
也可以用构造函数:
struct Point
{
public int X;
public int Y;
// 构造函数
public Point(int x, int y)
{
X = x;
Y = y;
}
}
var p = new Point(3, 7);
Console.WriteLine($"点: ({p.X}, {p.Y})");
什么时候用结构体比较好?
- 适合小型“数据组合”(比如坐标、颜色、区间、日期时间)。
- 当你很在意内存和性能(比如数组里有几百万个点)。
- 当对象要像一个整体值那样工作(copy-paste就是复制!)。
不建议用结构体的情况:
- 对象很大(字段太多)。
- 需要继承体系。
- 经常需要按引用修改。
3. 结构体的特点和“坑”
拷贝
Point p1 = new Point(1, 2);
Point p2 = p1; // 这里是拷贝!
p2.X = 100;
Console.WriteLine(p1.X); // 1 —— 没变!
Console.WriteLine(p2.X); // 100
拷贝结构体会得到独立的副本
自动的默认值
Point p; // 字段X和Y=0,即使你没手动赋值!
可以是Nullable
如果你想让结构体能存null,要用特殊的nullable语法——类型名后面加问号。这样变量就能赋null了。
Point? p = null;
if (p == null)
Console.WriteLine("没有点");
4. 带自动属性和方法的结构体
结构体也能有方法、属性、事件,甚至静态成员。
public struct Range
{
public int Start { get; set; }
public int End { get; set; }
public int Length => End - Start;
public override string ToString() => $"[{Start}..{End}]";
}
例子:复数的结构体
复数结构体,带方法和重写ToString()
struct Complex
{
public double Re;
public double Im;
public Complex(double re, double im)
{
Re = re;
Im = im;
}
public double Abs() => Math.Sqrt(Re * Re + Im * Im);
public override string ToString() => $"{Re} + {Im}i";
}
var z = new Complex(1, 2);
Console.WriteLine(z); // 1 + 2i
Console.WriteLine(z.Abs()); // 2.236...
GO TO FULL VERSION