C#传参方式

C#传参方式

  • 一、默认传递
  • [二、`ref` 引用传递(双向通信)](#二、ref 引用传递(双向通信))
  • [三、`out` 输出参数(只出不进)](#三、out 输出参数(只出不进))
  • [四、`in` 只读传递(性能优化利器)](#四、in 只读传递(性能优化利器))
  • [五、`params` 可变参数](#五、params 可变参数)
传递方式 关键字 底层机制 值类型表现 引用类型表现 典型使用场景
默认值传递 复制一份数据(值类型复制内容,引用类型复制内存地址) 方法内修改不影响外部 方法内修改属性会影响外部;但重新 new 不影响外部 绝大多数常规方法调用
引用传递 ref 传递变量的真实内存地址 方法内修改直接影响外部 方法内修改属性或重新 new 都直接影响外部 需要方法修改外部传入的变量(需提前初始化),必须加 ref
输出参数 out 传递变量的真实内存地址 方法内必须重新赋值,外部才能获取新值 方法内必须重新赋值,外部才能获取新对象 方法需要返回多个结果(不要求传入前初始化),必须加 out
只读引用 in 传递内存地址,但加上只读保护 方法内不可修改,避免大结构体复制开销 方法内不可修改引用,不可重新 new 传递大型 struct 时的性能优化(必须初始化),可加 in,也可省略
可变参数 params 编译器自动将多个参数打包为数组 接收任意数量的同类型参数 接收任意数量的同类型参数 类似 string.Format() 的灵活传参

一、默认传递

引用类型传递的是地址的副本。这意味着你可以用这个副本去修改原对象的属性,但你不能把原对象"换掉"

c# 复制代码
public class Person { public string? Name { get; set; } }

public static void DefaultTest(Person p, int num)
{
	p.Name = "李四"; // 修改属性:外部原对象会被修改!
	num = 999;           // 修改值类型:外部原变量不受影响
	p = new Person { Name = "测试" }; // 重新赋值:外部原对象不受影响!
}

static void Main(string[] args)
{
	Person p = new Person();
	p.Name = "张三";

	int num = 10;
	Console.WriteLine($"修改前: name:{p.Name}, num:{num}");
	DefaultTest(p, num);
	Console.WriteLine($"修改后: name:{p.Name}, num:{num}");
}

二、ref 引用传递(双向通信)

使用 ref 时,形参和实参指向完全相同的内存,任何操作都会同步到外部

c# 复制代码
public class Person { public string? Name { get; set; } }

public static void RefTest(ref Person p, ref int num)
{
	num = 999; // 外部变量直接变成 999
	p = new Person { Name = "李四" }; // 外部变量直接指向新对象
	// p.Name = "李四"; // 修改属性:外部原对象会被修改!
}

static void Main(string[] args)
{
	Person p = new Person();
	p.Name = "张三";

	int num = 10;
	Console.WriteLine($"修改前: name:{p.Name}, num:{num}");
	RefTest(ref p, ref num);
	Console.WriteLine($"修改后: name:{p.Name}, num:{num}");
}

三、out 输出参数(只出不进)

out 适合用来返回多个结果,传入前不需要初始化,但方法内部必须赋值

c# 复制代码
static void Main(string[] args)
{
	int a;
	if (int.TryParse("10", out a))
	{
		Console.WriteLine($"a:{a}");
	}

	int b;
	if (int.TryParse("xyz", out b))
	{
		Console.WriteLine($"b:{b}");
	}
	else
	{
		Console.WriteLine($"b:{b}");
	}
}

四、in 只读传递(性能优化利器)

主要用于大型结构体(struct),避免复制带来的内存开销,同时保证数据安全

c# 复制代码
public struct Point
{
	public int X; public int Y; public int Z;
}

public static void InTest(in Point point)
{
	//point = new Point(); // ❌ 编译报错:不能修改
	//point.X = 10;      // ❌ 编译报错:不能修改属性
	var copy = point;             // ✅ 可以读取
}

五、params 可变参数

必须放在参数列表的最后

c# 复制代码
static void Main(string[] args)
{
	Console.WriteLine("{0},{1},{2},{3}", "hello", "world", "hello", "world");
}