C# 中 ref、out 和 in 关键字的用法是什么?
在 C# 中,大多数方法可以有零个或多个参数,这些参数定义了必须提供给方法的数据。任何调用该方法的代码都必须将数据(称为参数)传递给该方法。方法将输入声明为参数,并且这些参数由调用代码以参数的形式提供。
例如,考虑以下方法和后续方法调用。
static void Greet(string greeting){
Console.WriteLine(greeting);
}
...
Greet("Hello");在上面的示例中,greeting 是 Greet() 方法的参数,“Hello” 是传递给方法的参数。
当您调用方法并传递参数时,它们是按值传递的,这意味着在传递给方法时会创建值的副本。在方法内部对参数所做的任何更改都不会反映到原始变量上。
using System;
int number = 8;
Increase(number);
Console.WriteLine(number); // prints 8
static void Increase(int num){
num = num + 1;
Console.WriteLine(num); // prints 9
}当您传递引用类型变量(例如对象)时,C# 仍然按值复制**引用**,因为变量保存的是引用,而不是实际的对象。因此,即使复制了引用变量的副本,它们也都会引用内存中的同一个对象。因此,方法内部变量对对象所做的任何更改都对方法外部的变量可见。
using System;
var john = new User{
Name = "John",
Salary = 50000
};
Promote(john);
Console.WriteLine(john.Salary); // prints 60000
static void Promote(User u){
u.Salary += 10000;
Console.WriteLine(u.Salary); // prints 60000
}但是,如果您在方法内部更改变量本身的值,则该更改不会反映到方法外部,因为只更改了副本,而不是实际的对象。例如,我们可以在方法内部将参数赋值为 null,而实际变量将保持不变。
using System;
var john = new User{
Name = "John",
Salary = 50000
};
Promote(john);
Console.WriteLine(john.Salary); // prints 50000
static void Promote(User u){
u = null;
}C# 允许使用三个不同的修饰符关键字来控制方法的参数。
ref 修饰符
C# 允许您使用ref修饰符按引用传递参数。传递的变量是引用类型还是值类型都无关紧要。参数和参数都将引用同一个内存位置。
在下面的示例中,将参数 u 设置为 null 也会使 john 变量为 null,从而导致空引用异常。
示例
using System;
var john = new User{
Name = "John",
Salary = 50000
};
Promote(ref john);
Console.WriteLine(john.Salary); // throws System.NullReferenceException
static void Promote(ref User u){
u = null;
}使用 ref 修饰符传递的参数必须在传递之前进行初始化。
out 修饰符
它类似于 ref 修饰符,除了
参数不必在进入函数之前进行初始化
参数必须在退出函数之前进行初始化(赋值)。
在下面的示例中,Hire 函数初始化一个新的用户对象,该对象通过 out 修饰符传递给它。请注意,在调用 Hire 方法时,变量 john 是即时声明的。
using System;
Hire(out User john);
Console.WriteLine(john.Salary); // prints 50000
static void Hire(out User u){
u = new User{
Name = "John",
Salary = 50000
};
}与ref修饰符一样,用out修饰符标记的变量是按引用传递的。
通常,out变量用于从函数获取多个返回值,如下所示:
using System;
var john = new User{
Name = "John",
Salary = 50000
};
bool shouldPromote = Raise(john.Salary, out double hike);
Console.WriteLine(shouldPromote); // True
Console.WriteLine($"Hike Amount = {hike}"); // prints 5000
static bool Raise(int salary, out double hike){
hike = salary * 0.1;
return hike < 7000;
}in 修饰符
它类似于ref和out参数,除了接受in参数值的方法不能修改参数。如果尝试修改,C# 编译器会生成编译时错误。
in参数可以防止编译器将大型值类型的内存复制到参数变量,同时防止对象意外修改。这使得它们在将大型值类型传递给方法时非常有用。
var point = new Coord();
Verify(point);
static void Verify(in Coord c){
// error: Cannot assign to variable 'in Coord' because it is a readonly variable
c = new Coord();
}
struct Coord{
public int X;
public int Y;
}示例
using System;
class Program{
static void Main(){
int number = 8;
Increase(number);
Console.WriteLine(number); // prints 8
var john = new User { Name = "John", Salary = 50000 };
Promote(john);
Console.WriteLine(john.Salary); // prints 60000
Leave(john);
Console.WriteLine(john.Salary); // prints 60000
LeaveByRef(ref john);
Console.WriteLine(john?.Salary); // prints nothing
User dave;
Hire(out dave);
Console.WriteLine(dave.Salary); // prints 50000
}
static void Increase(int num){
num = num + 1;
Console.WriteLine(num); // prints 9
}
static void Promote(User u){
u.Salary += 10000;
Console.WriteLine(u.Salary); // prints 60000
}
static void Leave(User u){
u = null;
}
static void LeaveByRef(ref User u){
u = null;
}
static void Hire(out User u){
u = new User{
Name = "John",
Salary = 50000
};
}
}
class User{
public string Name { get; set; }
public int Salary { get; set; }
}输出
9 8 60000 60000 60000 50000
数据结构
网络
关系数据库管理系统
操作系统
Java
iOS
HTML
CSS
Android
Python
C 编程
C++
C#
MongoDB
MySQL
Javascript
PHP