c# 结构体的使用

结构体是一种值类型,用于封装一组相关的数据,使其成为一个单一的变量单元。它和类(Class)超级类似,但存在一些关键性的区别,这些区别决定了它们的使用场景。

1. 核心概念:值类型 vs. 引用类型

这是理解结构体最根本的一点。

  • 结构体是值类型:当一个结构体变量被赋值给另一个变量,或者作为参数传递给方法时,发生的是内容的完整拷贝。修改拷贝后的数据不会影响原始数据。
Point p1 = new Point(10, 20);
Point p2 = p1; // 这里进行的是值拷贝,p2 是 p1 的一个独立副本

p2.X = 100; // 只修改 p2
Console.WriteLine(p1.X); // 输出: 10 (p1 完全没有被影响)
Console.WriteLine(p2.X); // 输出: 100

类是引用类型:当类对象被赋值或传递时,发生的是引用的拷贝(类似于拷贝一个快捷方式)。两个变量指向内存中的同一个对象。修改其中一个,另一个也会看到变化。

MyClass obj1 = new MyClass { Data = 10 };
MyClass obj2 = obj1; // 这里拷贝的是引用,obj2 和 obj1 指向同一个对象

obj2.Data = 100; // 通过 obj2 修改对象
Console.WriteLine(obj1.Data); // 输出: 100 (obj1 也看到了修改)
Console.WriteLine(obj2.Data); // 输出: 100

2. 如何定义结构体

使用 struct 关键字定义。其成员定义方式与类几乎完全一致(字段、属性、方法、构造函数等)。

// 定义一个表明点的结构体
public struct Point
{
    // 字段
    public int X;
    public int Y;

    // 带参数的构造函数(必须初始化所有字段)
    public Point(int x, int y)
    {
        this.X = x;
        this.Y = y;
    }

    // 方法
    public void Print()
    {
        Console.WriteLine($"({X}, {Y})");
    }

    // 属性
    public double DistanceFromOrigin => Math.Sqrt(X * X + Y * Y);
}

结构体的特点与限制

  1. 隐式继承:所有结构体都隐式继承自 System.ValueType,而 ValueType 又继承自 object。这意味着结构体拥有 ToString()GetHashCode() 等方法,但不能显式继承其他类或结构体(不支持继承)。
  2. 构造函数
  3. 你可以定义带参数的构造函数,但必须初始化所有实例字段
  4. 编译器会自动生成一个无参构造函数new Point()),你不能自己定义一个无参构造函数。这个无参构造函数会将所有字段设置为其默认值(0、false、null 等)。
  5. 字段初始化不能在结构体声明时直接初始化实例字段
public struct BadExample
{
    // public int Value = 10; // 编译错误!不允许这样初始化
    public int Value; // 正确,必须在构造函数中初始化
}
  1. 性能思考:由于是值类型,结构体一般分配在栈(Stack) 上(但这并非绝对,例如作为类的成员时,它会随类实例分配在堆上)。对于小型、生命周期短的数据,这可以减少垃圾回收(GC)的压力,性能更高。但对于大型结构体,频繁的拷贝操作可能会带来性能损失。

4. 何时使用结构体(Guidelines)

根据微软的官方提议,在以下情况下思考使用结构体:

  • 逻辑上表明一个简单的值,类似于原始类型(int, double)。
  • 实例大小应小于 16 字节。如果太大,拷贝成本会很高,反而降低性能。
  • 它是不可变的(Immutable)。这是一个超级重大的实践。创建后,其状态不应再改变。这样能避免值拷贝语义带来的困惑。
  • 它不会频繁地被装箱(Boxing)。(装箱是将值类型转换为 object 引用类型的过程,有性能开销)。
  • 不需要继承自其他类型或被其他类型继承

典型应用场景

  • 坐标点(Point
  • 复数(Complex
  • 颜色(Color)(RGBA值)
  • 轻量级的键值对(KeyValuePair
  • 其他简单的数据容器

5. 结构体 vs. 类 (总结)

特性

结构体 (Struct)

类 (Class)

类型

值类型

引用类型

分配位置

一般在线程栈上

托管堆上

赋值操作

拷贝内容

拷贝引用

继承

不能显式继承,隐式继承自 ValueType

支持继承和多态

构造函数

不能自定义无参构造函数

可以自定义无参构造函数

字段初始化

声明时不能初始化实例字段

声明时可以初始化实例字段

默认值

不能为 null(可空类型 Nullable 除外)

可以为 null

适用场景

小型、简单、不可变的数据

复杂的对象、需要继承、需要共享引用

总结

C# 中的结构体是一种轻量级的值类型,适用于封装小型、简单的数据集合,尤其是那些不可变的数据。它的值语义(拷贝行为)是其与类的核心区别。正确使用结构体可以提高应用程序的性能,但错误地使用(例如创建过大的可变结构体)则会适得其反。在大多数表明复杂逻辑或状态的场景中,类依旧是首选

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
风清云淡的头像 - 鹿快
评论 共1条

请登录后发表评论