使用 ref 关键字的主要目的是表示变量的值可以通过传入的函数来更改。当您按值传递变量时,函数内部的更新不会影响原始副本。
当您需要多个返回值并为返回值构建一个特殊的结构或类时,它非常有用(并且更快)。例如,
public void Quaternion.GetRollPitchYaw(ref double roll, ref double pitch, ref double yaw){
roll = something;
pitch = something;
yaw = something;
}
这是不受限制地使用指针的语言中非常基本的模式。在 c/c++ 中,您经常看到以类和数组作为指针的值传递原语。C# 正好相反,所以 'ref' 在上述情况下很方便。
当您通过 ref 将要更新的变量传递给函数时,只需 1 次写入操作即可获得结果。但是,当返回值时,您通常会写入函数内部的某个变量,将其返回,然后再次将其写入目标变量。根据数据,这可能会增加不必要的开销。无论如何,这些是我在使用 ref 关键字之前通常会考虑的主要事项。
有时 ref 在 c# 中像这样使用时会快一点,但不足以将其用作 goto 性能的理由。
这是我在一台 7 岁的机器上使用下面的代码通过 ref 和值传递和更新 100k 字符串的结果。
输出:
迭代次数:10000000 byref:165ms byval:417ms
private void m_btnTest_Click(object sender, EventArgs e) {
Stopwatch sw = new Stopwatch();
string s = "";
string value = new string ('x', 100000); // 100k string
int iterations = 10000000;
//-----------------------------------------------------
// Update by ref
//-----------------------------------------------------
sw.Start();
for (var n = 0; n < iterations; n++) {
SetStringValue(ref s, ref value);
}
sw.Stop();
long proc1 = sw.ElapsedMilliseconds;
sw.Reset();
//-----------------------------------------------------
// Update by value
//-----------------------------------------------------
sw.Start();
for (var n = 0; n < iterations; n++) {
s = SetStringValue(s, value);
}
sw.Stop();
long proc2 = sw.ElapsedMilliseconds;
//-----------------------------------------------------
Console.WriteLine("iterations: {0} \nbyref: {1}ms \nbyval: {2}ms", iterations, proc1, proc2);
}
public string SetStringValue(string input, string value) {
input = value;
return input;
}
public void SetStringValue(ref string input, ref string value) {
input = value;
}