C# 中 Class 与 Struct 的核心差异:引用类型与值类型对比

木白
木白
发布时间:2026-10-15 | 3人浏览过
原创

在 C# 开发中,合理选择 class 与 struct 对程序性能至关重要。class 是引用类型,存储在堆中,传递的是对象引用;struct 是值类型,通常存储在栈中,传递时进行数据拷贝。本文将详细对比两者在内存管理、默认值、继承规则及构造函数方面的差异,并通过实际代码演示其行为表现。

一、核心类型与内存存储

理解 class 和 struct 的首要任务是掌握它们的内存模型:

  • Class(引用类型):实例分配在堆内存中,变量本身存储的是指向堆中对象的引用(指针)。当使用 = 赋值给另一个变量时,仅复制引用地址,两个变量指向同一对象。
  • Struct(值类型):实例通常直接包含在栈内存中(或在引用类型的字段内作为内联数据)。变量包含完整的数据。赋值操作会将所有字段值复制到新位置,彼此独立。

二、Class 的特性细节

第1步:了解类的引用行为

由于类是引用类型,多个引用可以指向同一个内存地址。修改其中一个引用的属性,会影响所有指向该对象的引用。

XClass xClass = null; // 语法正确,类可以为null
XClass xClass3 = new XClass() { Id = 7, Name = "天晴之海" };
XClass xClass4 = xClass3; // 此时xClass4与xClass3指向同一内存地址
// ReferenceEquals(xClass3, xClass4) 将返回 true

第2步:构造函数规则

C# 中的类具有灵活的构造函数定义:

  • 默认情况:如果未显式定义任何构造函数,编译器会自动提供一个无参构造函数。
  • 自定义情况:一旦定义了带参数的构造函数,且未手动添加无参构造函数,系统将不再提供默认的无参构造函数,必须通过参数初始化或显式补充无参构造。

第3步:字符串的特殊性

虽然 string 在底层是 class(引用类型),但其具有不可变性。对字符串的任何修改(如拼接)都会创建新的对象实例,而非修改原内存中的数据。因此在逻辑上常被视为按“值”处理。

三、Struct 的特性细节

第1步:值类型的不可空性与默认值

Struct 是值类型,不能直接赋值为 null。其默认值由字段类型的默认值决定(例如 int 为 0,bool 为 false)。

XStruct xStruct = null; // 编译错误!
// 如需使用null,需借助可空类型
Nullable<XStruct> nullableStruct = null;
// 或简化写法
XStruct? nullableStruct = null;

第2步:继承与基类约束

所有 struct 都隐式继承自 System.ValueType(而 ValueType 又继承自 Object)。因此:

  • 不支持继承其他类或结构。
  • 不允许显式定义无参构造函数。系统始终提供隐藏的无参构造函数用于初始化默认值。
  • 无法在声明处直接赋予字段初始值(如 int Id = 0; 在结构中是非法的)。

第3步:相等性判断

由于 struct 重写了 Equals 方法,基于值的比较判定两个 struct 实例是否相等。若所有字段值一致,则视为相等,即便它们是不同的内存实例。

四、综合测试与现象观察

为了验证上述理论,我们构建了一个控制台应用程序 GenericTemplateDemo,分别对类和结构的赋值、比较进行测试。

第4步:代码实现

using System;

namespace GenericTemplateDemo
{
    class Program
    {
        static void Main(string[] args)
        {
            // --- 结构 (Struct) 测试 ---
            Console.WriteLine($"结构的默认值为类型名: {default(XStruct)}, 类型名为【{typeof(XStruct)}】");
            
            // 1. 不同实例但值相同
            XStruct xStruct1 = new XStruct("ABC") { Id = 5 };
            XStruct xStruct2 = new XStruct("ABC") { Id = 5 };
            Console.WriteLine($"[结构] 值比较 Equals: {xStruct1.Equals(xStruct2)}"); // True
            Console.WriteLine($"[结构] 引用比较 ReferenceEquals: {ReferenceEquals(xStruct1, xStruct2)}"); // False

            // 2. 赋值测试
            XStruct xStruct3 = new XStruct("修吾") { Id = 8 };
            XStruct xStruct4 = xStruct3; // 值拷贝
            Console.WriteLine($"[结构] 赋值后引用比较: {ReferenceEquals(xStruct3, xStruct4)}"); // False

            // --- 类 (Class) 测试 ---
            Console.WriteLine($"\n类的默认值为null: {default(XClass) == null}");

            // 1. 不同实例但值相同
            XClass xClass1 = new XClass("毒瘴泉") { Id = 6 };
            XClass xClass2 = new XClass("毒瘴泉") { Id = 6 };
            Console.WriteLine($"[类] 值比较 Equals: {xClass1.Equals(xClass2)}"); // False (默认Object.Equals为引用比较)
            Console.WriteLine($"[类] 引用比较 ReferenceEquals: {ReferenceEquals(xClass1, xClass2)}"); // False

            // 2. 赋值测试
            XClass xClass3 = new XClass("天晴之海") { Id = 7 };
            XClass xClass4 = xClass3; // 引用拷贝
            Console.WriteLine($"[类] 赋值后引用比较: {ReferenceEquals(xClass3, xClass4)}"); // True
        }
    }

    /// <summary>
    /// 测试用的结构
    /// </summary>
    public struct XStruct
    {
        // 自定义有参构造函数
        public XStruct(string name)
        {
            Id = 0;
            Name = name;
        }
        // 注意:结构体字段不能在声明处赋初值
        public int Id;
        public string Name;
    }

    /// <summary>
    /// 测试用的类
    /// </summary>
    public class XClass
    {
        public XClass()
        {
            // 空实现
        }
        public XClass(string name)
        {
            Id = 0;
            Name = name;
        }
        // 自动属性允许赋初值
        public int Id { get; set; }
        public string Name { get; set; }
    }
}

第5步:运行结果图示

程序运行输出如下所示,清晰展示了结构与类在不同场景下的内存行为:

五、选择建议

在实际开发中选择数据类型时,可以参考以下原则:

  1. 轻量级数据结构:如果数据量小且生命周期短(如坐标点 Point、颜色 Color),优先考虑 struct,减少 GC(垃圾回收)压力并提升栈访问速度。
  2. 复杂对象与多态:如果数据量大、需要继承体系、或者需要传递引用语义(一个地方修改影响全局),应使用 class。
  3. 不可变数据:对于无需修改的常量配置数据,值类型往往更安全且高效。

总结

以上就是C#中class与struct区别与使用的详细内容,更多关于C#高级编程与内存管理的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表