假设一个方法正在改变通过引用传递的参数的值.在整个应用程序中或仅在方法返回后,此操作的效果是否立即可见?
下面是一个重要的例子:
int x = 0; void Foo(ref int y) { ++y; Console.WriteLine(x); } Foo(ref x);
它可以在http://csharppad.com/gist/915318e2cc0da2c2533dfa7983119869下的C#Pad中运行
该函数Foo
可以访问变量,x
因为它在同一范围内,并且恰好在调用站点接收对它的引用.如果效果++y
是立即的,那么输出应该是1
,但我可以想象一个编译器生成代码,例如,将本地值存储在寄存器中,并在返回之前的某个时间转储到内存中.语言规范是否确保输出1
是否允许抖动优化,使输出实现依赖?
在整个应用程序中或仅在方法返回后,此操作的效果是否立即可见?
它立即可见 - 因为基本上,你最终传递的是变量本身,而不是变量的值.您正在修改完全相同的存储位置.
实际上,您可以在同一方法中看到这一点:
using System; class Test { static void Main(string[] args) { int a = 10; Foo(ref a, ref a); } static void Foo(ref int x, ref int y) { x = 2; Console.WriteLine(y); // Prints 2, because x and y share a storage location } }
这是在5.1.5节的C#5规范中:
引用参数不会创建新的存储位置.相反,引用参数表示与作为函数成员或匿名函数调用中的参数给出的变量相同的存储位置.因此,参考参数的值始终与基础变量相同.
反过来也是如此 - 如果底层变量的值以某种其他方式改变,那么该改变将在方法中可见.使用委托更改值的示例:
using System; class Test { static void Main(string[] args) { int a = 10; Foo(ref a, () => a++); } static void Foo(ref int x, Action action) { Console.WriteLine(x); // 10 action(); // Changes the value of a Console.WriteLine(x); // 11 x = 5; action(); Console.WriteLine(x); // 6 } }