【C#】C#中值类型和引用类型参数传递的区别

C#中值类型和引用类型参数传递的区别

1. C#中的参数传递机制

在C#中,参数传递主要分为两种情况:

  • 值类型传递 :传递的是变量的副本,方法内的修改不会影响原始变量。
  • 引用类型传递 :传递的是对象引用的副本,方法内对对象属性的修改会影响原始对象。

普通函数参数传递的区别主要取决于参数的类型:

  • 如果参数是值类型 (如int、struct等):方法内的修改不会影响原始变量。
  • 如果参数是引用类型 (如class、interface等):方法内对对象属性的修改会影响原始对象。

示例

csharp 复制代码
using System;

namespace ParamPassingDemo
{
    // 引用类型(类)
    class Person
    {
        public string Name { get; set; }
        public int Age { get; set; }

        public override string ToString()
        {
            return $"Person{{Name='{Name}', Age={Age}}}";
        }
    }

    // 值类型(结构体)
    struct Point
    {
        public int X { get; set; }
        public int Y { get; set; }

        public override string ToString()
        {
            return $"Point{{X={X}, Y={Y}}}";
        }
    }

    class Program
    {
        // 修改引用类型参数的方法
        static void ModifyPerson(Person person)
        {
            // 直接修改引用指向的对象的属性
            person.Name = "Modified Alice";
            person.Age = 30;
            
            Console.WriteLine($"ModifyPerson方法内: {person}");
        }

        // 修改值类型参数的方法
        static void ModifyPoint(Point point)
        {
            // 修改的是副本的属性
            point.X = 100;
            point.Y = 200;
            
            Console.WriteLine($"ModifyPoint方法内: {point}");
        }

        // 创建新对象并赋值给引用参数
        static void ReplacePerson(Person person)
        {
            // 创建新对象并赋值给参数(修改的是参数指向的引用)
            person = new Person { Name = "New Person", Age = 40 };
            
            Console.WriteLine($"ReplacePerson方法内: {person}");
        }

        // 使用ref关键字传递值类型
        static void ModifyPointRef(ref Point point)
        {
            // 修改的是原始对象的属性
            point.X = 100;
            point.Y = 200;
            
            Console.WriteLine($"ModifyPointRef方法内: {point}");
        }

        static void Main(string[] args)
        {
            Console.WriteLine("=== C# 参数传递演示 ===");
            Console.WriteLine();

            // 1. 引用类型参数传递
            Console.WriteLine("1. 引用类型(类)参数传递:");
            Person alice = new Person { Name = "Alice", Age = 25 };
            Console.WriteLine($"调用前: {alice}");
            ModifyPerson(alice);
            Console.WriteLine($"调用后: {alice}");
            Console.WriteLine("结论: 引用类型参数传递时,方法内对对象的修改会影响原始对象");
            Console.WriteLine();

            // 2. 值类型参数传递
            Console.WriteLine("2. 值类型(结构体)参数传递:");
            Point p1 = new Point { X = 10, Y = 20 };
            Console.WriteLine($"调用前: {p1}");
            ModifyPoint(p1);
            Console.WriteLine($"调用后: {p1}");
            Console.WriteLine("结论: 值类型参数传递时,方法内的修改不会影响原始对象");
            Console.WriteLine();

            // 3. 替换引用类型参数指向的对象
            Console.WriteLine("3. 替换引用类型参数指向的对象:");
            Person bob = new Person { Name = "Bob", Age = 35 };
            Console.WriteLine($"调用前: {bob}");
            ReplacePerson(bob);
            Console.WriteLine($"调用后: {bob}");
            Console.WriteLine("结论: 替换参数指向的引用不会影响原始对象");
            Console.WriteLine();

            // 4. 使用ref关键字传递值类型
            Console.WriteLine("4. 使用ref关键字传递值类型:");
            Point p2 = new Point { X = 50, Y = 60 };
            Console.WriteLine($"调用前: {p2}");
            ModifyPointRef(ref p2);
            Console.WriteLine($"调用后: {p2}");
            Console.WriteLine("结论: 使用ref关键字可以让方法修改原始值类型对象");
            Console.WriteLine();

            Console.WriteLine("=== 总结 ===");
            Console.WriteLine("1. 值类型: 默认传递副本,方法内修改不影响原始对象");
            Console.WriteLine("2. 引用类型: 默认传递引用的副本,方法内修改对象属性会影响原始对象");
            Console.WriteLine("3. 替换引用: 修改参数指向的引用不会影响原始对象");
            Console.WriteLine("4. ref关键字: 可以让方法直接修改原始参数");
        }
    }
}

运行结果

bash 复制代码
=== C# 参数传递演示 ===

1. 引用类型(类)参数传递:
调用前: Person{Name='Alice', Age=25}
ModifyPerson方法内: Person{Name='Modified Alice', Age=30}
调用后: Person{Name='Modified Alice', Age=30}
结论: 引用类型参数传递时,方法内对对象的修改会影响原始对象

2. 值类型(结构体)参数传递:
调用前: Point{X=10, Y=20}
ModifyPoint方法内: Point{X=100, Y=200}
调用后: Point{X=10, Y=20}
结论: 值类型参数传递时,方法内的修改不会影响原始对象

3. 替换引用类型参数指向的对象:
调用前: Person{Name='Bob', Age=35}
ReplacePerson方法内: Person{Name='New Person', Age=40}
调用后: Person{Name='Bob', Age=35}
结论: 替换参数指向的引用不会影响原始对象

4. 使用ref关键字传递值类型:
调用前: Point{X=50, Y=60}
ModifyPointRef方法内: Point{X=100, Y=200}
调用后: Point{X=100, Y=200}
结论: 使用ref关键字可以让方法修改原始值类型对象

=== 总结 ===
1. 值类型: 默认传递副本,方法内修改不影响原始对象
2. 引用类型: 默认传递引用的副本,方法内修改对象属性会影响原始对象
3. 替换引用: 修改参数指向的引用不会影响原始对象
4. ref关键字: 可以让方法直接修改原始参数
相关推荐
椒颜皮皮虾྅44 分钟前
让文档不止于文字:DeploySharp + PP-Structure,打通版面分析与表格重建
开发语言·学习·c#·.net·cuda
Eider19981 小时前
Python基础知识之并发相关-2
开发语言·前端·python
第九序言T1 小时前
Python 数据处理进阶(二十二)用 Pandas 做一次完整的用户行为分析
开发语言·python·数据分析·pandas
云和数据.ChenGuang1 小时前
再论深拷贝和浅拷贝
开发语言·人工智能·python·1024程序员节
晚风予卿云月2 小时前
【C++高并发内存池】 2.ThreadCache设计
开发语言·c++·高并发内存池·tcmalloc
Dovis(誓平步青云)3 小时前
拖动关键帧角色就抽动,动画编辑器怎样补齐中间状态
开发语言·前端·javascript·机器学习·编辑器
行走的陀螺仪3 小时前
Claude Code 从入门到实战(二):Bash工具、Plan模式与后台任务
开发语言·bash
努力努力再努力wz3 小时前
【Lua 入门系列】从执行模型到事件驱动:一文理解 Lua 有栈协程、挂起恢复与协作式调度
开发语言·lua
椒颜皮皮虾྅3 小时前
一套 C# 接口,解锁四类视觉任务:DeploySharp 分类、分割、关键点与旋转框实战
开发语言·分类·c#
2603_965896623 小时前
JavaScript 原型与原型链
开发语言·前端·javascript