C#值类型与引用类型的核心区别解析

阿澈
阿澈
发布时间:2026-10-16| 4人浏览过
原创

C#的类型体系分为值类型和引用类型,理解两者在赋值机制、内存布局及对象比较上的本质区别,是编写高效C#代码的关键。本文将通过实例演示这两类类型在处理数据副本、分配位置及比较逻辑时的具体差异。

一、变量赋值的差异:副本 vs 引用

值类型和引用类型最显著的区别在于变量赋值的行为。对于值类型,赋值操作会创建数据的一个完整副本;而对于引用类型,赋值仅仅是复制对象的引用(指针),使多个变量指向内存中的同一个实例。

第1步:定义测试结构体与类

首先定义一个名为 Ref 的引用类型和一个名为 Val 的值类型,二者包含相同的属性逻辑:

using System;

namespace ConsoleApp1
{
    /// <summary>
    /// 一个简单的引用类型
    /// </summary>
    public class Ref
    {
        public int iValue { get; set; }

        public Ref(int i)
        {
            iValue = i;
        }

        public override string ToString()
        {
            return $"iValue的值为:{iValue.ToString()}";
        }
    }

    /// <summary>
    /// 一个简单的值类型
    /// </summary>
    public struct Val
    {
        public int Value { get; set; }

        public Val(int i)
        {
            Value = i;
        }

        public override string ToString()
        {
            return $"Value的值为:{Value.ToString()}";
        }
    }
}

第2步:执行赋值并观察变化

在 Main 方法中,分别创建实例并进行赋值与修改操作,观察相互影响:

class Program
{
    static void Main(string[] args)
    {
        // 测试引用类型的赋值
        Ref ref1 = new Ref(1);
        Ref ref2 = ref1;
        ref2.iValue = 2; // 修改 ref2,ref1 也会受到影响

        // 测试值类型的赋值
        Val val1 = new Val(1);
        Val val2 = val1;
        val2.Value = 2;  // 修改 val2,val1 保持不变

        Console.WriteLine($"ref1:{ref1}");
        Console.WriteLine($"ref2:{ref2}");
        Console.WriteLine($"val1:{val1}");
        Console.WriteLine($"val2:{val2}");
    }
}

在引用类型赋值中,Ref ref2 = ref1 将 ref1 的引用赋给 ref2,两者指向同一对象。如图所示:

而在值类型赋值中,val1 和 val2 各自拥有独立的内存空间和数据副本。当 val2 改变时,val1 不受影响。图示如下:

代码运行后的控制台输出结果验证了上述分析:

二、内存分配位置的不同

除了赋值行为,两类类型在内存管理上也有明确界限:

  • 引用类型:对象本体存储在堆(Heap)上,变量本身存储的是指向堆内存的地址。
  • 值类型:对象直接存储在堆栈(Stack)上(如果是局部变量),或者作为引用类型字段嵌入在堆中。由于堆栈访问速度快,值类型通常在性能密集型场景下更具优势。

三、继承结构与 Equals 比较的差异

由于所有值类型都隐式继承自 System.ValueType,而引用类型大多继承自 System.Object(除非显式重写),这导致了它们在对象相等性比较时的不同表现。

第1步:构造两组内容相同的独立实例

为了公平比较,分别创建两个内容完全相同但地址不同的引用类型和值类型实例:

// 创建两个相同的引用类型实例
Ref ref1 = new Ref(1);
Ref ref2 = new Ref(1);

// 创建两个相同的值类型实例
Val val1 = new Val(1);
Val val2 = new Val(1); 

第2步:调用 Equals 方法进行对比

使用 Equals 方法判断两组实例是否相等:

Console.WriteLine(ref1.Equals(ref2)); // 引用类型未重写 Equals,默认进行引用比较
Console.WriteLine(val1.Equals(val2)); // 值类型默认进行值(内容)比较

程序输出结果如下:

结果显示:ref1.Equals(ref2) 返回 false,因为两者是不同的对象引用;而 val1.Equals(val2) 返回 true,因为它们的内部数值完全一致。

总结

C# 中值类型与引用类型的区别可以概括为以下几点:

  • 赋值机制:值类型赋值产生新副本,互不影响;引用类型赋值共享同一实例。
  • 内存布局:值类型主要在堆栈上运行,效率高;引用类型本体在堆上分配。
  • 比较逻辑:值类型继承 System.ValueType 实现基于内容的比较;引用类型若未重写 Equals,则仅比较引用地址是否相同。

以上就是C#值类型和引用类型区别的详细内容,更多关于C#基础知识优化的资料请关注本站其它相关文章!

相关标签:

免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。

Python 相关产品和应用

全部下载
Selenium

Selenium

4.51.0 · Windows

用于浏览器自动化和 Web 测试的 Python 工具。

scikit-learn

scikit-learn

1.9.1 · Windows

常用 Python 机器学习算法与模型评估工具库。

Black

Black

26.10.1 · Windows

强调一致性的 Python 自动代码格式化工具。

Ruff

Ruff

0.17.1 · macOS

由 Rust 编写的高速 Python 代码检查和格式化工具。

pytest

pytest

9.1.1 · Windows

简洁而强大的 Python 自动化测试框架。

FastAPI

FastAPI

0.146.0 · Windows

高性能 Python API 框架,支持类型提示和自动接口文档。

Flask

Flask

3.1.3 · Windows

轻量灵活的 Python Web 应用框架。

Django

Django

6.1.2 · Windows

成熟的 Python Web 框架,适合构建内容站点和业务系统。

Spyder

Spyder

6.1.7 · Windows

面向科学计算与数据分析的 Python 集成开发环境。

SciPy

SciPy

1.18.1 · Windows

面向科学、工程和技术计算的 Python 算法库。