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关键字: 可以让方法直接修改原始参数